使用useState的“ setter”函数作为回调引用是否安全?

时间:2019-12-09 07:03:49

标签: reactjs react-hooks react-context react-suspense

useState钩子的setter函数用作回调ref函数是否安全?这会给Suspense或其他即将发生的React变化带来麻烦吗?如果“是,可以”,那太酷了!如果“不”,为什么不呢?如果“也许”,那么什么时候可以还是不可以?

我之所以问是因为我的一个组件在调用DOM API之前需要安装三个引用。这些必需的引用中有两个是通过JSX ref属性在同一组件中分配的“常规”引用。稍后,将通过React上下文在深度嵌套的组件中分配另一个ref。我需要一种方法来在所有三个引用都安装后强制重新渲染父组件,并在卸载任何引用时强制进行useEffect清理。

最初,我编写了自己的回调引用处理程序,该处理程序称为useState setter,我将其存储在上下文提供程序中。但是后来我意识到useState设置器完成了我自己的回调引用所做的一切。使用setter而不是编写自己的回调ref函数是否安全?还是有一种更好和/或更安全的方式来做我想做的事情?

我尝试使用Google搜索"useState" "callback ref"(以及其他类似的关键字变体),但结果没有帮助,除了@theKashey出色的use-callback-ref软件包之外,我肯定会在其他地方使用它(例如当我需要将回调ref传递给需要RefObject的组件时,或者当我既需要回调又需要在本地使用ref时),但是在这种情况下,当ref更改时,所有回调需要做的就是设置状态变量,所以安东的包裹似乎在这里太过分了。

下面是一个简化的示例,位于https://codesandbox.io/s/dreamy-shockley-5dc74

import * as React from 'react';
import { useState, forwardRef, useEffect, createContext, useContext, useMemo } from 'react';
import { render } from 'react-dom';

const Child = forwardRef((props, ref) => {
  return <div ref={ref}>This is a regular child component</div>;
});

const refContext = createContext();
const ContextUsingChild = props => {
  const { setValue } = useContext(refContext);
  return <div ref={setValue}>This child uses context</div>;
};

const Parent = () => {
  const [child1, setChild1] = useState(null);
  const [child2, setChild2] = useState(null);
  const [child3, setChild3] = useState(null);

  useEffect(() => {
    if (child1 && child2) {
      console.log(`Child 1 text: ${child1.innerText}`);
      console.log(`Child 2 text: ${child2.innerText}`);
      console.log(`Child 3 text: ${child3.innerText}`);
    } else {
      console.log(`Child 1: ${child1 ? '' : 'not '}mounted`);
      console.log(`Child 2: ${child2 ? '' : 'not '}mounted`);
      console.log(`Child 3: ${child3 ? '' : 'not '}mounted`);
      console.log(`In a real app, would run a cleanup function here`);
    }
  }, [child1, child2, child3]);

  const value = useMemo(() => ({ setValue: setChild3 }), []);

  return (
    <refContext.Provider value={value}>
      <div className="App">
        This is text in the parent component
        <Child ref={setChild1} />
        <Child ref={setChild2} />
        <ContextUsingChild />
      </div>
    </refContext.Provider>
  );
};

const rootElement = document.getElementById('root');
render(<Parent />, rootElement);

1 个答案:

答案 0 :(得分:-1)

useState “setter” 函数在渲染周期内保持相同的引用,所以这些应该可以安全使用。甚至 mentioned 可以在依赖数组中省略它们:

<块引用>

(setCount 函数的身份保证是稳定的,所以省略是安全的。)

你可以直接传递setter函数:

<refContext.Provider value={setChild3}>

...然后阅读:

const ContextUsingChild = props => {
  const setChild3 = useContext(refContext);
  return <div ref={setChild3}>This child uses context</div>;
};