【问题标题】:Updating state to the same state directly in the component body直接在组件主体中将状态更新为相同状态
【发布时间】:2022-10-19 12:03:14
【问题描述】:

假设我有这个简单的虚拟组件:

const Component = () => {

  const [state, setState] = useState(1);

  setState(1);

  return <div>Component</div>
}

在此代码中,我将状态更新为相同像以前一样直接在组件主体中的值。但是,即使值保持不变,这也会导致过多的重新渲染。

据我所知,在 React.useState 中,如果状态值更新为与以前相同的值 -React 不会重新渲染组件.那么为什么会发生在这里呢?

然而,如果我尝试用 useEffect 做一些类似的事情而不是直接在组件主体中:

const Component = () => {

  const [state, setState] = useState(1);

  useEffect(()=>{
    setState(1);
  },[state])

  return <div>Component</div>
}

这是不是导致无限循环并完全按照以下规则进行如果状态保持不变,React 将不会重新渲染组件。

所以我的问题是:为什么当我直接在组件主体中执行它时会导致无限循环,而在 useEffect 中却不会?

如果有人对此有一些“幕后”解释,我将不胜感激!

【问题讨论】:

    标签: javascript reactjs react-hooks infinite-loop react-component


    【解决方案1】:

    长话短说

    第一个示例是无意的副作用,将无条件触发重新渲染,而第二个示例是有意的副作用,并允许 React 组件生命周期按预期运行。

    回答

    我认为你在混淆“渲染阶段”当 React 调用组件的 render 方法来计算下一个渲染周期与我们通常所说的“渲染周期”的差异时,组件生命周期的“提交阶段”当 React 更新 DOM 时。

    查看组件生命周期图:

    请注意,在 React 函数组件中全部的函数体是“渲染”方法,函数的返回值是我们想要刷新或提交到 DOM 的值。现在我们都应该知道,React 组件的“render”方法被认为是一个没有副作用的纯函数。换句话说,渲染结果是 state 和 props 的纯函数。

    在第一个例子中,入队状态更新是一个意外的副作用被调用的外部正常的组件生命周期(即挂载、更新、卸载).

    const Component = () => {
      const [state, setState] = useState(1);
    
      setState(1); // <-- unintentional side-effect
    
      return <div>Component</div>;
    };
    

    它在“渲染阶段”触发重新渲染。 React 组件从来没有机会完成渲染周期,所以没有什么可以“区分”或摆脱的,因此渲染循环发生了。

    排队状态更新的另一个例子是故意的副作用. useEffect 钩子在渲染周期结束时运行下一个 UI 更改被刷新或提交到 DOM。

    const Component = () => {
      const [state, setState] = useState(1);
    
      useEffect(() => {
        setState(1); // <-- intentional side-effect
      }, [state]);
    
      return <div>Component</div>;
    }
    

    useEffect 挂钩是大致函数组件等同于类组件的componentDidMountcomponentDidUpdatecomponentWillUnmount生命周期方法。它保证在组件挂载时至少运行一次,而不管依赖性如何。该效果将运行一次并将状态更新加入队列。 React 将“看到”入队值与当前状态值相同,并且惯于触发重新渲染。

    同样,您可以使用 useEffect 挂钩并完全删除依赖项数组,这样的效果可能会触发每个渲染周期。

    const Component = () => {
      const [state, setState] = useState(1);
    
      useEffect(() => {
        setState(1);
      });
    
      return <div>Component</div>;
    }
    

    同样,useEffect 钩子回调保证至少被调用一次,将状态更新加入队列。 React 将“看到”排队的值与当前状态值相同,并且惯于触发重新渲染。

    这里的要点是不是将无意和意外的副作用编码到您的 React 组件中,因为这会导致和/或导致错误代码。

    【讨论】:

    • 这就是对此的完美解释。太感谢了!
    【解决方案2】:

    当调用 setState(1) 时,你也会触发重新渲染,因为这就是 hooks 固有的工作方式。这是对底层机制的一个很好的解释:

    How does React.useState triggers re-render?

    【讨论】:

    • 这就是钩子的工作原理改变在该州。在 React 触发重新渲染之前 - 它总是将状态的先前值与新值进行比较,如果相同 - React 将不是重新渲染。如果它重新渲染,那么这个比较的意义何在?useEffect 是如何工作的?
    猜你喜欢
    • 2022-10-19
    • 2019-07-14
    • 1970-01-01
    • 2021-11-02
    • 2022-01-03
    • 1970-01-01
    • 1970-01-01
    • 2018-05-21
    • 2021-10-25
    相关资源
    最近更新 更多