簡體   English   中英

React Hooks - 設置最后一個值?

[英]React Hooks - set last value?

我正在嘗試編寫基本的鈎子來在滾動時獲取 currentScroll、lastScroll、scrollSpeed。

function useDocScroll() {
  const isClient = typeof window === "object"

  function getScroll() {
    return isClient
      ? window.pageYOffset || document.documentElement.scrollTop
      : undefined
  }

  const [docScroll, setDocScroll] = useState(getScroll)
  const [lastScroll, setLastScroll] = useState(null)
  const [scrollSpeed, setScrollSpeed] = useState(Math.abs(docScroll - lastScroll))

  useEffect(() => {
    if (!isClient) {
      return false
    }

    function handleScroll() {
      setDocScroll(getScroll())
      setLastScroll(getScroll())  // <-- why is this working?
      // setLastScroll(docScroll) // <-- why is this not working?

      setScrollSpeed(Math.abs(docScroll - lastScroll)) // <-- why is this not working?
    }

    window.addEventListener("scroll", handleScroll)
  }, [])

  return [docScroll, lastScroll, scrollSpeed]
}

似乎當我執行setLastScroll(getScroll()) ,它可以很好地保存最后一個滾動值。

但我不明白,因為當handleScroll()觸發時, getScroll()值不應該保持不變嗎? 我不明白為什么setDocScroll(getScroll())setLastScroll(getScroll())有不同的值。

另外,我想我可以做setLastScroll(docScroll) ,意思是“用當前的 docScroll 值設置 lastScroll 值”,但它只是在 docScroll 值更改時打印“0”。

為什么是這樣? 我想更好地理解。

+) 而且我無法獲得由docScrolllastScroll計算的scrollSpeed ,但我不知道如何獲得這些值。

編輯分心-golick-c89w3

我認為為什么您的代碼不起作用是因為以下兩個原因:

  1. setDocScroll之后直接使用docScroll將不起作用,因為 setState 是異步任務。 不能保證在執行下docScroll語句之前更新docScroll
  2. 由於在某些特定元素(可能)內發生滾動,您得到0 由於document.documentElement指向html元素並且里面沒有滾動。 所以你收到0

解決方案:

您不需要多個useState 由於滾動事件發射太頻繁,我認為使用useReducer來減少渲染次數是個好主意。 無論是在根級別還是在某個元素內部,了解滾動發生的位置很重要。

對於以下解決方案,我提出了:

如果滾動發生在根級別(html 元素),則無需將元素傳遞給useDocScroll 如果滾動發生在特定元素內,則需要傳遞元素引用。

const initState = {
  current: 0,
  last: 0,
  speed: 0,
};

function reducer(state, action) {
  switch (action.type) {
    case "update":
      return {
        last: state.current,
        current: action.payload,
        speed: Math.abs(action.payload - state.current) || 0,
      };
    default:
      return state;
  }
}

const isClient = () => typeof window === "object";
function useDocScroll(element = document.documentElement) {
  const [{ current, last, speed }, dispatch] = useReducer(reducer, initState);

  function getScroll() {
    return isClient() ? element.scrollTop : 0;
  }

  function handleScroll() {
    dispatch({ type: "update", payload: getScroll() });
  }

  useEffect(() => {
    if (!isClient()) {
      return false;
    }

    element.addEventListener("scroll", handleScroll);

    return () => element.removeEventListener("scroll", handleScroll);
  }, []);

  return [current, last, speed];
}

例子:

如果滾動發生在窗口內

const {current, last, speed} = useDocScroll()

如果滾動發生在特定元素

const {current, last, speed} = useDocScroll(document.getElementById("main"))

由於關閉,它不起作用:

useEffect(() => {
  if (!isClient) {
    return false;
  }

  function handleScroll() {
    setDocScroll(getScroll());

    // On calling handleScroll the values docScroll & lastScroll
    // are always will be of the first mount,
    // the listener "remembers" (closures) such values and never gets updated
    setLastScroll(docScroll);
    setScrollSpeed(Math.abs(docScroll - lastScroll));

    // v Gets updated on every call
    setLastScroll(getScroll());
  }

  // v Here you assigning a callback which closes upon the lexical scope of
  // docScroll and lastScroll
  window.addEventListener('scroll', handleScroll);
}, []);

要修復它,一個可能的解決方案可以是參考( useRef )和功能setState

例如:

setScrollSpeed(lastScroll => Math.abs(getScroll() - lastScroll))

不知道為什么lastScrolled需要:

function useDocScroll() {
  const [docScroll, setDocScroll] = useState(getScroll());
  const lastScrollRef = useRef(null);
  const [scrollSpeed, setScrollSpeed] = useState();

  useEffect(() => {
    if (!isClient) {
      return false;
    }

    function handleScroll() {
      const lastScroll = lastScrollRef.current;
      const curr = getScroll();
      setScrollSpeed(Math.abs(getScroll() - (lastScroll || 0)));
      setDocScroll(curr);

      // Update last
      lastScrollRef.current = curr;
    }

    window.addEventListener('scroll', handleScroll);
  }, []);

  return [docScroll, lastScrollRef.current, scrollSpeed];
}

編輯 hidden-architecture-p8xbi

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM