☝️上文提及:可以通过组件中的重要信息是否由组件自身
state
还是外部prop
驱动来区分「受控组件」&「非受控组件」。
换言之,props
是对外的,state
是对内的
props
:只读,父组件通过 props
传递给子组件其所需要的状态;子组件内部不能直接修改props
,只能在父组件中修改。state
:可变,是组件内部维护的一组用于反映组件UI变化的状态集合。本篇会 ✓ 🇨🇳 总结 React 中的 state 状态
回顾一下1: ① react 有两种原因会导致组件的渲染,其中 State setter 函数 更新变量会触发 React 渲染组件; ② State 变量 用于保存渲染间的数据。
👀 State = 存放数据 + 触发重新渲染
const [index, setIndex] = useState(0);
function handleClick() {
setIndex(i => i + 1);
}
index
的初始值被 useState(0)
设置为 0
;index
) 会保存上次渲染的值;setIndex
) 可以更新 state 变量并触发 React 重新渲染组件。核心:把当前的数据复制到新对象中
const [person, setPerson] = useState({name: '', age: 0})
setPerson({
...person,
age: e.target.value // 只覆盖 age 字段
})
setPerson({
...person,
[e.target.name]: e.target.value // 动态命名
})
‼️注意:...
展开语法本质是是“浅拷贝”——它只会复制一层。这使得它的执行速度很快,但是也意味着当你想要更新一个嵌套属性时,你必须得多次使用展开语法2。
setPerson({
...person, // 复制其它字段的数据
artwork: { // 替换 artwork 字段
...person.artwork, // 复制之前 person.artwork 中的数据
city: 'New Delhi' // 但是将 city 的值替换为 New Delhi!
}
});
核心:将 React state 中的数组视为只读的
每次要更新一个数组时,需要把一个新的数组传入 state 的 setting 方法中。
避免使用 (会改变原始数组) | 推荐使用 (会返回一个新数组) | |
---|---|---|
添加元素 | push,unshift | concat,[...arr] 展开语法(例子) |
删除元素 | pop,shift,splice | filter,slice(例子) |
替换元素 | splice,arr[i] = ... 赋值 | map(例子) |
排序 | reverse,sort | 先将数组复制一份(例子) |
在 开篇:通过 state 阐述 React 渲染
setInterval
示例中曾提及:一个 state 变量的值永远不会在一次渲染的内部发生变化。
React 会等到事件处理函数中的 所有 代码都运行完毕再处理你的 state 更新。
export default function Counter() {
const [number, setNumber] = useState(0);
return (
<>
<h1>{number}</h1>
<button onClick={() => {
setNumber(n => n + 1);
setNumber(n => n + 1);
setNumber(n => n + 1);
}}>+3</button>
</>
)
}
appendChild()
DOM API 将其创建的所有 DOM 节点放在屏幕上。React 仅在渲染之间存在差异时才会更改 DOM 节点。
示例3:有一个组件,它每秒使用从父组件传递下来的不同属性重新渲染一次。 ‼️注意,文本不会在组件重渲染时消失。
export default function Clock({ time }) {
return (
<>
<h1>{time}</h1>
<input />
</>
);
}
状态与渲染树中的位置相关: 相同位置的相同组件会使得 state 被保留下来,否则会重置。关于此部分的详实,在下一篇专题讲述!