【问题标题】:How to force an update for a functional component?如何强制更新功能组件?
【发布时间】:2020-12-14 06:01:20
【问题描述】:

我正在学习redux,想了解useSelector如何更新组件,因为组件没有自己的状态。

我了解useSelector()将组件订阅到商店,当商店更新时,组件也会更新。

类组件有this.forceUpdate(),但函数式组件没有。

如何强制更新功能组件?

【问题讨论】:

  • 如果 useSelector 没有更新组件,你可能改变了 reducer 中的状态。

标签: reactjs redux


【解决方案1】:

你可以这样做

添加一个可以更改的虚拟状态以可靠地启动重新渲染。

const [rerender, setRerender] = useState(false);

...
//And whenever you want to re-render, you can do this
setRerender(!rerender);

这将重新渲染组件,因为组件总是在状态更改时重新渲染

【讨论】:

    【解决方案2】:

    首先,我想提一下,当你使用 useSelector 钩子时,你不需要强制更新。每当更新选定的状态值时,都会自动进行重新渲染。

    但是如果你需要强制更新功能组件你可以使用这种方法。

    import React, { useState } from 'react';
    
    //create your forceUpdate hook
    function useForceUpdate(){
        const [value, setValue] = useState(0); // integer state
        return () => setValue(value => ++value); // update the state to force render
    }
    
    function MyComponent() {
        // call your hook here
        const forceUpdate = useForceUpdate();
    
        return (
            <div>
                {/*Clicking on the button will force to re-render like force update does */}
                <button onClick={forceUpdate}>
                    Click to re-render
                </button>
            </div>
        );
    }
    

    我强烈建议避免使用此 hack,在 99% 的问题中,您无需强制更新即可解决它们。但无论如何,很高兴知道在功能组件中也存在这种可能性。

    【讨论】:

    • 是的,我知道 useSelector 更新组件,但我想知道它是如何工作的
    • 当一个动作被分派到 Redux 存储时,useSelector() 仅在选择器结果看起来与上一个结果不同时才强制重新渲染。有关幕后发生的事情的更多信息,您可以在这里找到:react-redux.js.org/api/hooks#equality-comparisons-and-updates
    【解决方案3】:

    也许这样的事情可以帮助你:

    在类组件中,您可以传递如下所示的属性...

    <Element onSomethingHappen={
       ()=>{
       if(shouldComponentUpdate())
          this.forceUpdate();
    }}/>
    

    在函数组件中你可以像这样调用更新器:

    function FunctionComponent(props){
        //When you need it you can update like this one...
        props.onSomethingHappen(); 
        // Here you are ;) let me know if this helps you
    }
    

    【讨论】:

      【解决方案4】:

      react-redux 包依赖于react/react-dom 的渲染引擎来触发使用useSelector 钩子的给定组件的重新渲染。

      如果您查看useSelectorsource,您会注意到useReducer 的使用:

      const [, forceRender] = useReducer((s) => s + 1, 0)
      

      顾名思义 (forceRender),redux 使用它通过 react 触发重新渲染。

      随着 v8react-redux 的实现,此机制的实现发生了变化,但仍依赖于 react-hooks 进行重新渲染。


      如果您对 React 如何处理重新渲染感到好奇,请查看 this excellent SO answer。它提供了有关 react-hooks 如何与调用组件相关联的实现细节的一个很好的入口。

      我在这里不再重复 Ryan,而是总结一下

      渲染器保留对当前渲染组件的引用。在此渲染期间执行的所有钩子(无论它们嵌套在自定义钩子中的深度如何)最终都属于该组件。 因此,useReducer 与您在其中调用useSelector 的组件相关联。

      useReducer 的 dispatch 函数会触发该组件的重新渲染(React 要么调用类组件的 render() 方法,要么执行功能组件的函数体)。


      如果您想知道react-redux 如何确定何时应该强制重新渲染(通过使用useReducer),请再看看useSelectorsource code

      Redux 使用订阅者模式来获得状态更新的通知。如果 redux 的根状态被更新,会发生以下事情:

      1. useSelector 应用程序中的钩子重新运行它们的选择器功能
      2. 这个重新选择的状态与之前选择的状态进行比较(默认通过===比较)。 useSelector 的第二个参数可以是一个比较函数来改变这种行为
      3. 如果重新选择的状态与之前选择的状态不同,则会通过 useReducer 挂钩触发重新渲染。

      订阅者模式非常类似于反应,但可能有助于节省许多重新渲染。与重新渲染相比,调用多个 useSelector 钩子成本更低。

      【讨论】:

        猜你喜欢
        • 2021-02-26
        • 2019-11-15
        • 2021-10-23
        • 1970-01-01
        • 1970-01-01
        • 2020-08-04
        • 1970-01-01
        • 2021-10-07
        • 2018-11-10
        相关资源
        最近更新 更多