React
colocation
自动嵌套
- 自动嵌套: 当你在
**/dashboard**
目录下创建页面时,这些页面会自动作为**children**
传递给**<Layout />**
组件。这意味着这些页面会被渲染在布局组件定义的结构中。
route groups
state如同一张快照
设置 state 只会为下一次渲染变更 state 的值。在第一次渲染期间,number
为 0
。这也就解释了为什么在 那次渲染中的onClick
处理函数中,即便在调用了 setNumber(number + 1)
之后,number
的值也仍然是 0
:
1 | <button onClick={() => { |
以下是这个按钮的点击事件处理函数通知 React 要做的事情:
setNumber(number + 1)
:number
是0
所以setNumber(0 + 1)
。- React 准备在下一次渲染时将
number
更改为1
。
- React 准备在下一次渲染时将
setNumber(number + 1)
:number
是0
所以setNumber(0 + 1)
。- React 准备在下一次渲染时将
number
更改为1
。
- React 准备在下一次渲染时将
setNumber(number + 1)
:number
是0
所以setNumber(0 + 1)
。- React 准备在下一次渲染时将
number
更改为1
。
- React 准备在下一次渲染时将
尽管你调用了三次 setNumber(number + 1)
,但在 这次渲染的 事件处理函数中 number
会一直是 0
,所以你会三次将 state 设置成 1
。这就是为什么在你的事件处理函数执行完以后,React 重新渲染的组件中的 number
等于 1
而不是 3
。
随时间变化的 state
一个 state 变量的值永远不会在一次渲染的内部发生变化, 即使其事件处理函数的代码是异步的。在 那次渲染的<font style="color:#DF2A3F;">onClick</font>
内部,<font style="color:#DF2A3F;">number</font>
的值即使在调用 <font style="color:#DF2A3F;">setNumber(number + 5)</font>
之后也还是 <font style="color:#DF2A3F;">0</font>
。它的值在 React 通过调用你的组件“获取 UI 的快照”时就被“固定”了。
state
像这样的代码是有问题的,因为它改变了 state 中现有的对象:
1 | position.x = e.clientX; |
但是像这样的代码就 没有任何问题,因为你改变的是你刚刚创建的一个新的对象:
1 | const nextPosition = {}; |
事实上,它完全等同于下面这种写法:
1 | setPosition({ |
只有当你改变已经处于 state 中的 现有 对象时,mutation 才会成为问题。而修改一个你刚刚创建的对象就不会出现任何问题,因为 还没有其他的代码引用它。改变它并不会意外地影响到依赖它的东西。这叫做“局部 mutation”。你甚至可以 在渲染的过程中 进行“局部 mutation”的操作。这种操作既便捷又没有任何问题!
…
setPerson({
...person,
email: e.target.value
});
请注意 ...
展开语法本质是是“浅拷贝”——它只会复制一层。这使得它的执行速度很快,但是也意味着当你想要更新一个嵌套属性时,你必须得多次使用展开语法。
immer
通过使用 Immer,你写出的代码看起来就像是你“打破了规则”而直接修改了对象:
1 | const [person, updatePerson] = useImmer(.....) |
但是不同于一般的 mutation,它并不会覆盖之前的 state!
请注意当使用 Immer 时,类似 **artwork.seen = nextSeen**
这种会产生 mutation 的语法不会再有任何问题了:
1 | updateMyTodos(draft => { |
这是因为你并不是在直接修改原始的 state,而是在修改 Immer 提供的一个特殊的 draft
对象。同理,你也可以为 draft
的内容使用 push()
和 pop()
这些会直接修改原值的方法。
在幕后,Immer 总是会根据你对 draft
的修改来从头开始构建下一个 state。这使得你的事件处理程序非常的简洁,同时也不会直接修改 state。
==和===
<font style="color:rgb(25, 27, 31);background-color:rgb(248, 248, 250);">useCallback</font>
和 <font style="color:rgb(25, 27, 31);background-color:rgb(248, 248, 250);">useMomeo</font>
的区别
**<font style="color:rgb(25, 27, 31);background-color:rgb(248, 248, 250);">useCallback</font>**
和 **<font style="color:rgb(25, 27, 31);background-color:rgb(248, 248, 250);">useMemo</font>**
都是用于性能优化的 React 钩子函数,它们都可以避免不必要的重新计算或重新渲染。虽然它们看起来很相似,但它们有几个重要的区别。
首先,**<font style="color:rgb(25, 27, 31);background-color:rgb(248, 248, 250);">useCallback</font>**
返回一个缓存的回调函数,而 **<font style="color:rgb(25, 27, 31);background-color:rgb(248, 248, 250);">useMemo</font>**
返回一个缓存的值。这意味着 **<font style="color:rgb(25, 27, 31);background-color:rgb(248, 248, 250);">useCallback</font>**
的主要作用是为一个函数创建缓存,而 **<font style="color:rgb(25, 27, 31);background-color:rgb(248, 248, 250);">useMemo</font>**
的主要作用是缓存一个值。
其次,它们接受的参数不同。**<font style="color:rgb(25, 27, 31);background-color:rgb(248, 248, 250);">useCallback</font>**
接受一个回调函数和一个依赖项数组,而 **<font style="color:rgb(25, 27, 31);background-color:rgb(248, 248, 250);">useMemo</font>**
接受一个函数和一个依赖项数组。在 **<font style="color:rgb(25, 27, 31);background-color:rgb(248, 248, 250);">useCallback</font>**
中,只有依赖项数组中的值发生变化时,才会重新创建回调函数。而在 **<font style="color:rgb(25, 27, 31);background-color:rgb(248, 248, 250);">useMemo</font>**
中,只有依赖项数组中的值发生变化时,才会重新计算值。
最后,它们的使用场景也不同。**<font style="color:rgb(25, 27, 31);background-color:rgb(248, 248, 250);">useCallback</font>**
适用于优化回调函数,避免不必要的重新渲染,并传递给子组件。而 **<font style="color:rgb(25, 27, 31);background-color:rgb(248, 248, 250);">useMemo</font>**
适用于优化计算开销较大的值,如大型数组或对象的计算。
综上所述,**<font style="color:rgb(25, 27, 31);background-color:rgb(248, 248, 250);">useCallback</font>**
和 **<font style="color:rgb(25, 27, 31);background-color:rgb(248, 248, 250);">useMemo</font>**
的主要区别在于它们的返回值类型和使用场景。需要根据具体的情况选择使用哪个钩子函数。
- Title: React
- Author: gaoyanchen
- Created at : 2024-09-13 19:07:05
- Updated at : 2024-10-17 11:24:02
- Link: https://gyc.660624.xyz/2024/09/13/React/
- License: This work is licensed under CC BY-NC-SA 4.0.