【问题标题】:React: save ref to state in a custom hookReact:将 ref 保存到自定义钩子中的状态
【发布时间】:2020-11-30 19:59:15
【问题描述】:

我想为一个元素创建一个 ref,将它保存在 state 中,然后在其他地方使用它。这是我目前所拥有的:

const Header = () => {
  const topElement = useRef();
  const { setRootElement } = useScrollToTop();

  useEffect(() => {
    setRootElement(topElement);
  }, []);

  return (
    <div ref={topElement}>
     ...
    </div>
  )
}

useScrollToTop 钩子:

export const useScrollToTop = () => {
  const [rootElement, setRootElement] = useState();

  const scrollToTop = () => {
    rootElement.current.scrollIntoView();
  };

  return {
    scrollToTop: scrollToTop,
    setRootElement: setRootElement
  };
};

在不同的组件中:

const LongList = () => {

    const { scrollToTop } = useScrollToTop();

    return (
       <div>
        ....
          <button onClick={() => scrollToTop()} />
       </div>
    );
}

setRootElemet 工作正常,它保存了我传递给它的元素,但是当我调用 scrollToTop() 时,该元素未定义。我在这里错过了什么?

【问题讨论】:

    标签: reactjs react-hooks ref


    【解决方案1】:

    问题可能是 topElement 最初为 null,而 useEffect 将触发 setRootElement 为 null。您需要将 topElement 保留在状态变量中并检查它何时更改并将 JSX 中的值设置为

    const [topElement, setTopElement] = useState(null);
    
    useEffect(() => {topElement && setRootElement(topElement);}, [topElement])
    
    return (
        <div ref={(ref) => setTopElement(ref)}>
             ...
        </div>
    );
    

    【讨论】:

      【解决方案2】:

      由于钩子本质上只是函数,因此调用之间没有共享状态。每次调用useScrollToTop 时,您都会得到一个新对象,该对象具有自己的scrollToTopsetRootElement。当您在 LongList 中调用 useScrollToTop 时,从不使用返回的 setRootElement,因此该实例 rootElement 将永远不会有值。

      您需要做的是调用useScrollToTop 并将返回的项目传递给它们各自的组件。此外,您可以直接使用 ref 并返回它,而不是在元素的钩子中使用状态。

      将这些放在一起,假设您的 App 结构类似于:

      • 应用程序
        • 标题
        • 长名单

      钩子:

      export const useScrollToTop = () => {
        const rootElement = useRef();
      
        const scrollToTop = () => {
          rootElement.current.scrollIntoView();
        };
      
        return {
          scrollToTop,
          rootElement,
        };
      };
      

      应用:

      ...
      const { scrollToTop, rootElement } = useScrollToTop();
      
      return (
        ...
        <Header rootElementRef={rootElement} />
        <LongList scrollToTop={scrollToTop} />
        ...
      );
      

      标题:

      const Header = ({ rootElementRef }) => {
        return (
          <div ref={rootElementRef}>
           ...
          </div>
        );
      }
      

      长名单:

      const LongList = ({ scrollToTop }) => {
        return (
          <div>
          ...
            <button onClick={() => scrollToTop()} />
          </div>
        );
      }
      

      【讨论】:

        猜你喜欢
        • 2021-09-28
        • 1970-01-01
        • 1970-01-01
        • 2021-06-02
        • 2019-10-01
        • 2021-09-29
        • 2020-08-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多