likes
comments
collection
share

React之修改state

作者站长头像
站长
· 阅读数 46

React渲染

在进行首次渲染时 React 会调用根组件。调用目标 DOM 节点的 createRoot,然后用你的组件调用 render 函数完成的:如下代码

const root = createRoot(document.getElementById('root'))
root.render(<Image />);

  • 对于数据更新时React,会调用内部状态更新的触发渲染函数组件,在严格模式下,React 会执行每个更新函数两次(正常会丢弃第二个结果)以便帮助你发现错误。

UI更新

state改变后,会根据当前渲染时的 state计算出新的组件。

React 会等到事件处理函数中的 所有 代码都运行完毕再处理你的 state 更新。 这就是为什么重新渲染只会发生在所有这些 setNumber() 调用 之后 的原因。比如下面的代码中,第二次setNumber里的number还是初始的0,因为在本次渲染任务的事件处理函数里,number的值是0.

import { useState } from 'react';

export default function Counter() {
  const [number, setNumber] = useState(0);

  return (
    <>
 
      <button onClick={() => {
        setNumber(number + 1);
        setNumber(number + 1);
      }}>+2</button>
    </>
  )
}

所以当想更新多个 state 变量——甚至来自多个组件的 state 变量——而不会触发太多的重新渲染时,我们可以传入更新函数,像setNumber(n => n + 1) 这样。只有在你的事件处理函数及其中任何代码执行完成 之后,UI 才会更新。这种特性也就是 批处理

更新函数执行原理

  1. React 会将此函数加入队列,以便在事件处理函数中的所有其他代码运行后进行处理。
  2. 在下一次渲染期间,React 会遍历队列并给你更新之后的最终 state。

模拟更新函数的批处理是如何执行的

export function getFinalState(baseState, queue) {
  let finalState = baseState;
 // baseState 初始值
 // queue 要完成的队列
 // getFinalState(baseState,[()=>{},()=>{},333])
queue.map(item=>{
  if(typeof item !=='function'){
    finalState=item
  }else {
    finalState=item(finalState)
  }
})
  return finalState;
}

更新state对象

  • 如果state是多个属性的对象,更新时也是setState({x:xxx,y:xxx}),如果更新部分属性,则可以用扩展运算符来copy其他的属性。
const [user,setUser]=useState({
name:'a',
age:'b',
})
 function handleNameChange(e) {
    setPerson({
      ...user,
      name:e.target.value
     // [e.target.name]: e.target.value 可以用作表单绑定上的通用方法
    });
  }
  • 层级深的对象:利用useImmer库,直接声明时使用const [user,setUser]=useImmer({})

  • 如果修改的state是数组

    • 不直接修改数组,创建一个它的拷贝,然后使用新的数组来更新它的状态,setState(newArray),
    • 用useImmer:这种方法并不是在直接修改原始的 state,而是在修改 Immer 提供的一个特殊的 draft 对象
    • [...arr, newItem]数组展开符的方法来向数组中添加新元素
    • filter() 和 map() 来创建一个新的经过过滤或者修改的数组。
转载自:https://juejin.cn/post/7244498421283831869
评论
请登录