【问题标题】:Render Once for Multiple set States using useState hook in React在 React 中使用 useState 钩子为多个集合状态渲染一次
【发布时间】:2021-06-01 08:46:17
【问题描述】:

有没有办法在更新多个状态后刷新/渲染一次功能组件?

例如:

const [first, setFirst] = useState(false);
const [second, setSecond] = useState(false);

调用时...

...
setFirst(true);
setSecond(true);

... 那么组件将刷新两次。是否可以同时设置并仅刷新(或渲染)一次?

【问题讨论】:

    标签: reactjs react-hooks react-component


    【解决方案1】:

    我没有看到它渲染两次。它只渲染一次,因为两个设置状态都批处理在一起。

    function App() {
    
      const [first, setFirst] = React.useState(false);
      const [second, setSecond] = React.useState(false);
      const counter = React.useRef(1)
      
      console.log('rendering: ', counter.current++)
     
      return (
        <button onClick={() => {
          setFirst(p => !p)
          setSecond(p => !p)
        }}>{first?'t1':'f1'}, {second?'t2':'f2'}</button>)
    }
    
    ReactDOM.render(<App />, document.getElementById('mydiv'))
    <script crossorigin src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>
    <body>
    <div id="mydiv"></div>
    </body>

    也许,由于使用StrictMode,您会看到它呈现两次。 StrictMode 将故意双重调用“渲染”和其他一些生命周期方法来检测 side-effects

    请参阅Why is React Component render counter getting incremented by 2? 以获取演示。


    更新:

    我认为您正在寻找@EvrenK 的answer 中提到的解决方案,即合并您的状态变量

    通常,在大多数情况下,您不必过于担心重新渲染,除非它成为一个明显的问题。如果它变得明显问题/延迟,您可以使用Reat.memo 避免由props 的更改引起的渲染

    没有办法,可以避免states变化引起的渲染。

    但是,有一种 hacky 方法可以更好地控制您的渲染:将所有(导致问题的少数)数据从状态移动到 ref / useRef em> 并创建一个状态数据来触发最终渲染。

    例子:

    const data1 = useRef()
    const data2 = useRef()
    const data3 = useRef()
    const [renderD1D2D3, setRenderD1D2D3] = useState(false)
    
    function handleChange1(newValue) {
      data1.current = newValue // Won't trigger render
    }
    function handleChange2(newValue) {
      data2.current = newValue // Won't trigger render
    }
    function handleChange3(newValue) {
      data3.current = newValue // Won't trigger render
    }
    
    function allGoodLetsRenderNow() {
      setRenderD1D2D3(prev => !prev) // Would trigger render
    }
    
    return (
      <>
        <div>{data1.current}</div>
        <div>{data2.current}</div>
        <div>{data3.current}</div>
      </>
    )
    
    

    【讨论】:

    • 这很有帮助,但不一定能回答问题。如果您可以在不关闭 StrictMode 的情况下提出解决方案,那么我会接受答案。 +1
    【解决方案2】:

    您可以将状态用作对象并将它们设置为一个,而不是像这样的单独状态

    const [exampleState, setExampleState] = useState(
      {fields: {
            fieldOne: false,
            fieldTwo: false
            }
       })
    

    可以这样设置

        setExampleState({...exampleState, fields: {
            fieldOne: true,
            fieldTwo: true
            },
       })
    

    【讨论】:

    • 这是我完全忘记 +1 的直接解决方案。
    猜你喜欢
    • 2022-01-24
    • 1970-01-01
    • 1970-01-01
    • 2021-02-27
    • 1970-01-01
    • 2021-02-21
    • 2020-10-22
    • 2020-04-29
    • 2021-05-31
    相关资源
    最近更新 更多