1.响应事件

正确调用回调函数

错误调用回调函数,会导致函数在组件渲染过程中立即触发函数,即使没有触发事件

image.png

父组件向子组件传递事件或参数:

在父组件的子组件上写属性,在子组件上接受事件通过props的传输
image.png

事件处理函数捕获子组件的事件

通常,我们会说事件会沿着树向上“冒泡”或“传播”:它从事件发生的地方开始,然后沿着树向上传播。
所以应该用e.stopPropagation()来阻止事件的传播,防止触发意想不到的,绑在父组件上的事件发生。
另外也提到了e.preventDefault(),举例子是阻止form表单的自动刷新页面的默认行为
image.png

2.state 组件的记忆

为什么要使用state,用变量为什么不行?
image.png
setState就会更新状态,并且触发react再次渲染组件

关于hook的陷阱

image.png
要保证对 Hook 的所有调用都发生在第一个 return前(第一次写小程序的泪~
原因:(简析,具体还需要看源码)
image.png
react的hooks依托于一个稳定的调用顺序,所以要求我们只在顶层调用reactHook,如果有条件判断,循环中调用hook,会打破这个顺序。

State 是隔离且私有的

你封装了一个组件,其中使用的usestate,那你渲染了多个相同的组件,更改一个组件的state时,其余的组件的state会改变吗?事实上并不会,因为多个组件的状态是相互独立的,私有的。
如果你希望这几个组件的状态是共享的,你应该把useState提取到公共父组件中去,更改父组件的state传给子组件。

这一章的最后一个挑战题里,提到一句话:State 变量仅用于在组件重渲染时保存信息。在单个事件处理函数中,普通变量就足够了。当普通变量运行良好时,不要引入 state 变量。
这就是为什么下面这个写法是正确的,相反使用react state是错误的
image.png

3.state 如同一张快照

为什么这里用变量是正确的,用state却是有问题的??
image.png

渲染会及时生成一张快照

我们前面就知道,setState会重新渲染一次页面,设置 state 只会为下一次渲染变更 state 的值
image.png

异步,同步的区别

每次触发setState,都是那此时此刻的state去制作一张用此时的state构建的快照,下图,onclick时,number的状态就是0,所以alert的是0,页面上的数字是5;下一次,alert是5,页面的数字{number}是10,
image.png但是我会发现,alert会阻塞页面的刷新,当alert框依然存在时,页面的数字还是老的state,因为这个onclick事件还没结束?只有当alert结束后,页面的数字才会刷新成+5后的数。
image.png
但是下面这个定时器例子里,页面先刷新了数字,后执行的定时器内还是老数据。其实这是因为计时器是异步执行的,不会阻塞浏览器的刷新。而alert同步执行,阻塞了浏览器的刷新。

一个 state 变量的值永远不会在一次渲染的内部发生变化

一个 state 变量的值永远不会在一次渲染的内部发生变化,即使事件处理的代码是异步的,我的理解是每一次渲染的 state 值都是固定的
image.png
可以看到,点击send,五秒后会执行alert,即使你在这期间修改了select的值,修改了textarea的值,但是不会影响五秒后的值,因为这个alert是一次渲染,内部的状态不会发生变化。

:::info React 会等到事件处理函数中的 所有 代码都运行完毕再处理你的 state 更新。 这就是为什么重新渲染只会发生在所有这些 setNumber() 调用 之后 的原因。 :::

那么如果我想在下次重新渲染之前,读取最新的状态?——————应该用状态更新函数。

4.把一系列 state 更新加入队列

状态更新函数

上文末提到的状态更新函数:
image.png

usestate的简单原理

课后挑战的这一题解释了计算state的方法,
image.png
如果setstate队列有很多操作,则分为是状态更新函数(function)或者直接赋值类型的。做不同的处理,这样usestate的预期输出就说得通了。

5.渲染和提交

触发一次渲染

有两种原因会导致组件的渲染:

组件的 初次渲染。

image.png

组件(或者其祖先之一)的 状态发生了改变。
  • 对于重渲染, React 将应用最少的必要操作(在渲染时计算!),以使得 DOM 与最新的渲染输出相互匹配。image.png
  • 也就是说,react的重新渲染的“颗粒度”是很小的

    6.更新state的对象类型

    1. const [position, setPosition] = useState({x: 0, y: 0});
    image.png

要更新对象类型的state,应该展开对象,对其中的键值对(基本类型)做重新赋值。

错误用法

image.png
是对象state,就不能简单的想当然的处理其中的字段,你正确的做法应该是展开对象,对其中的值做修改

正确做法

image.png

因此,处理大型表单时,优雅的做法是把所有字段放在一个对象去维护,而不是分成很多个state去处理。

动态事件处理函数

一个函数有很多个字段,难道处理其中的一个字段,就需要对其设置一个函数,并且展开其他 的字段,专门修改这个字段吗?react文档教了一个更优雅的写法:

技巧:使用e.target.name 引用了 这个 DOM 元素的 name 属性。做到了三合一的写法。
image.png

  1. import { useState } from 'react';
  2. export default function Form() {
  3. const [person, setPerson] = useState({
  4. firstName: 'Barbara',
  5. lastName: 'Hepworth',
  6. email: 'bhepworth@sculpture.com'
  7. });
  8. function handleChange(e) {
  9. setPerson({
  10. ...person,
  11. [e.target.name]: e.target.value
  12. });
  13. }
  14. return (
  15. <>
  16. <label>
  17. First name:
  18. <input
  19. name="firstName"
  20. value={person.firstName}
  21. onChange={handleChange}
  22. />
  23. </label>
  24. <label>
  25. Last name:
  26. <input
  27. name="lastName"
  28. value={person.lastName}
  29. onChange={handleChange}
  30. />
  31. </label>
  32. <label>
  33. Email:
  34. <input
  35. name="email"
  36. value={person.email}
  37. onChange={handleChange}
  38. />
  39. </label>
  40. <p>
  41. {person.firstName}{' '}
  42. {person.lastName}{' '}
  43. ({person.email})
  44. </p>
  45. </>
  46. );
  47. }

更新嵌套类型的对象

image.png
想要更新对象类型中对象的键值对,需要两次展开
image.png

**useImmer
为了处理这种嵌套的对象,react官网推荐了useimmer这个hook?
image.png

嘶。。。我感觉没啥必要,展开写就可以了。

总结:处理对象类型的state,直接修改对象本身是大忌,必须用set State({
})

7.更新state的数组类型

更新数组,应该使用能创建新数组的方法,而不是用改变元数组的方法
image.png
image.png