如何在 React 的无状态函数组件中初始化类实例?

Nos*_*omo 9 typescript reactjs react-native react-hooks

使用有状态模式,我通常在我的构造函数中初始化一种辅助类,并在一些组件生命周期方法中使用它的方法,如下所示:

class StatefulComponent extends Component {
  constructor(props) {
    super(props);
    this.helper = new HelperClass();
  }

  componentDidMount() {
    this.helper.doSomething();
  }

}
Run Code Online (Sandbox Code Playgroud)

现在,我想将相同的逻辑转换为像这样的无状态函数组件:

const StatelessFunction = (props) => {
   this.helper = new HelperClass();

   useEffect(() => {
     this.helper.doSomething();
   }, []);

}
Run Code Online (Sandbox Code Playgroud)

但是当我看到这个组件从一开始就被每个 prop 更改调用时,我很担心。这让我觉得我的类实例被一遍又一遍地创建。我错了吗?我能做些什么来防止重新创建我的班级并改用 ref 吗?

我遇到了useRef但不确定它是否适合我的情况。

HMR*_*HMR 22

回顾这个和一些评论,我可以看到不能信任 useMemo 不会再次运行 HelperClass 构造函数,并且 useRef 只会第一次渲染设置助手因为它的初始值不能是函数。可能 useState 是执行此操作的最简单和最可靠的方法:

const [helper] = useState(()=>new HelperClass());
Run Code Online (Sandbox Code Playgroud)

您可以使用 useMemo 创建 HelperClass 的实例并使用 useEffect 来调用它。给它们两个空的依赖数组意味着它们只会被称为“挂载”。我把 mount 放在引号中,因为 memo 只会在第一次渲染时被调用,而 effect 将在第一个渲染周期完成后被调用。

const StatelessFunction = props => {
  const helper = useMemo(() => new HelperClass(), []);
  useEffect(() => {
    helper.doSomething();
  }, [helper]);
  return (<JSX />);
};
Run Code Online (Sandbox Code Playgroud)

如果你唯一要做的就是调用 doSomething 并且不再使用 helper 实例,你可以使用 useEffect 来完成:

useEffect(() => {
  new HelperClass().doSomething();
}, []);
Run Code Online (Sandbox Code Playgroud)

如果您确实打算稍后使用帮助器实例,那么您可以将前面的示例与 useMemo 或 useRef 一起使用:

const helper = useRef();
useEffect(() => {
  helper.current = new HelperClass();
  //only called once after first render
  helper.current.doSomething();
}, []);
//you still have the helper instance as helper.current
Run Code Online (Sandbox Code Playgroud)

  • `useRef` 可能是一个更好的解决方案。来自 [docs](https://reactjs.org/docs/hooks-reference.html#usememo):“你可以依赖 useMemo 作为性能优化,而不是作为语义保证。将来,React 可能会选择“忘记”一些之前记忆的值并在下次渲染时重新计算它们,例如为屏幕外组件释放内存。编写代码,使其在没有 useMemo 的情况下仍然可以工作 - 然后添加它以优化性能。” (3认同)
  • 像这样使用 `useRef` 没有多大意义,但 `useMemo` 可以完成这项工作。 (2认同)
  • @nostromo821 useMemo 或 useRef 示例没有区别,它只是归结为偏好,并且由于多次提到它,所以我添加了它以完成。然而; 如果您计划在第一次渲染中使用 helper,则 useRef 将不起作用,因为效果只会在第一次渲染之后运行,并且 helper.current 在第一次渲染期间将是未定义的。 (2认同)