【问题标题】:How can I initialize a class instance in a stateless function component in React?如何在 React 的无状态函数组件中初始化类实例?
【发布时间】:2020-02-05 23:31:44
【问题描述】:

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

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

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

}

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

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

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

}

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

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

【问题讨论】:

  • useEffect + useRef
  • useRef 需要初始设置为 null 并在 useEffect 中正确设置 (ref.current) 以避免在渲染时重新创建

标签: reactjs typescript react-native react-hooks


【解决方案1】:

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

const [helper] = useState(()=>new HelperClass());

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

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

如果您唯一要做的就是调用 doSomething 并且不再使用辅助实例,那么您可以使用 useEffect 来完成:

useEffect(() => {
  new HelperClass().doSomething();
}, []);

如果您确实打算在以后使用帮助程序实例,那么您可以将前面的示例与 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

【讨论】:

  • 像这样使用 useRef 没有多大意义,但 useMemo 可以完成这项工作。
  • 感谢 HMR 和 @marzelin。使用 useMemo 来初始化实例正是我需要的。更清楚地说,我不仅会使用我的班级助手一次,而且会多次使用我的班级助手,尤其是在特定道具发生变化时。我现在在想为什么我需要使用 useRef 而不是 useMemo 而后者有更多的优势?有没有我更喜欢 useRef 的具体案例?
  • @nostromo821 在 useMemo 或 useRef 示例中没有区别,它只是归结为偏好,因为它被多次提及,所以我添加它以完成。然而;如果您计划在第一次渲染中使用 helper,那么 useRef 将不起作用,因为效果只会在第一次渲染之后运行,并且在第一次渲染期间 helper.current 将是未定义的。
  • useRef 可能是一个更好的解决方案。来自docs:“你可能依赖 useMemo 作为性能优化,而不是语义保证。在未来,React 可能会选择“忘记”一些以前记忆的值并在下一次渲染时重新计算它们,例如释放内存用于离屏组件。编写您的代码,使其在没有 useMemo 的情况下仍然可以工作——然后添加它以优化性能。”
  • useState 也不保证该函数只执行一次。请参阅here 以获得它执行多次的演示。在useEffect 之外执行的所有内容都假定没有副作用,并且应该可以使用任意参数执行而不会导致问题。我认为没有办法保证回调只执行一次。
【解决方案2】:

我会选择useMemo 解决方案,但您可以使用useRef + useEffect 来解决一些困惑:

const StatelessFunction = (props) => {
   const helper = useRef(); // ref is equivalent of instance prop

   useEffect(() => {
     helper.current = new HelperClass();
     helper.current.doSomething();
   }, []); // this is equivalent of componentDidMount
}

【讨论】:

    【解决方案3】:

    您是对的,useRef 允许您在重新渲染中保持相同的 HelperClass 实例

    const StatelessFunction = (props) => {
       const helper = useRef(new HelperClass())
    
       useEffect(() => {
         helper.current.doSomething();
       }, []);
    }
    

    【讨论】:

    猜你喜欢
    • 2020-10-18
    • 2023-03-08
    • 1970-01-01
    • 2019-10-26
    • 1970-01-01
    • 2020-08-04
    • 2014-08-25
    • 2022-10-04
    • 1970-01-01
    相关资源
    最近更新 更多