Browse Source

下课

pull/76/head
jingxun 2 years ago
parent
commit
48ee45440a
  1. 136
      day18/note/lesson046_getSnapshotBeforeUpdate.md

136
day18/note/lesson046_getSnapshotBeforeUpdate.md

@ -12,3 +12,139 @@
以上便是上节课的主要内容。
## 更新流程
![](https://file.lynchow.com/react%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F(%E6%96%B0).png)
我们先来看流程图,上节课我们说了一下挂载时那一块,和旧版生命周期唯一的区别是`getDerivedStateFromProps`钩子,而且我们也说了这个钩子应用场景罕见,只作了解,那么作为新增钩子中的另一个`getSnapshotBeforeUpdate`用得也不多。但是这个钩子和`getDerivedStateFromProps`又不太一样。那么我们接下来就看一下。
## 验证
首先这个钩子是什么在什么时候调用的?是不是在`render`和`componentDidUpdate`之间?而在旧的生命周期中这两个钩子之间是没有任何其他生命周期钩子在被调用的。
那么首先我们先来验证一下,这个调用顺序:
```jsx
class Count extends React.Component {
constructor(props) {...}
componentDidMount() {...}
componentWillUnmount() {...}
getDerivedStateFromProps() {
console.log("Count--getDerivedStateFromProps");
return null;
}
shouldComponentUpdate() {
console.log("Count--shouldComponentUpdate");
return true;
}
getSnapshotBeforeUpdate() {console.log("Count--getSnapshotBeforeUpdate");}
componentDidUpdate() {console.log("Count--componentDidUpdate");}
render() {
console.log("Count--render");
...
}
add = () => {...};
unmount = () => {...};
force = () => {...}
}
```
我们来看代码,我们并没有把`getDerivedStateFromProps`钩子给删掉,而是返回了`null`因为返回`null`的话是不会影响我们的`state`驱动页面更新的功能的。为什么我们不把这个钩子删掉呢?看流程图,因为这个钩子是更新流程的一个环节,我们为了完整展现整个流程,使用我们保留了这个钩子,只是返回了`null`使得我们的更新能够正常进行。
而且从流程图上面来看,我们如果需要通过`state`更新驱动页面更新,那么我们是不是要把`shouldComponentUpdate`钩子的返回值返回`true`才能正常往下进行?另外还有一点,如果我们写了`getSnapshotBeforeUpdate`钩子的话就一定要写`componentDidUpdate`钩子,否则:
![image-20220104150228713](https://file.lynchow.com/image-20220104150228713.png)
控制台中就会提示你说`getSnapshotBeforeUpdate`钩子应该和`componentDidUpdate`钩子一起使用,而你却只定义了`getSnapshotBeforeUpdate`。所以说`componentDidUpdate`钩子不能忘。那好我来看一下效果:
![image-20220104150430725](https://file.lynchow.com/image-20220104150430725.png)
我们来看,报错了,但是钩子的执行顺序没有任何问题。先是构造器,然后`getDerivedStateFromProps`钩子,热爱和`render`来挂载组件,挂载完了之后调用`componentDidMount`,当我们点击了`Add`按钮之后,触发`setState`,直接调用`getDerivedStateFromProps`钩子,然后到了阀门,判断是否允许组件更新,而我们的阀门一直是打开的,就会继续往下走,通过`render`更新组件,在执行完`render`之后执行了`getSnapshotBeforeUpdate`。从控制台中可以看出,这个钩子执行成功了,语法上是没有错误的。但是报了一个错误警告。当这个钩子执行完之后,调用了`componentDidUpdate`钩子。
首先来说,我吗成功验证了各个生命周期钩子的调用顺序与流程图完全一致。那么接下来我们来看看调用`getSnapshotBeforeUpdate`钩子报错是个什么情况?
报错信息说`getSnapshotBeforeUpdate`钩子必须返回一个`snapshot`值或者`null`,但是我们却返回了`undefined`。这个看着是不是和`getDerivedStateFromProps`钩子的要求还挺像的?关键我们不知道啥是`snapshot`值,那么我先保证不报错,我们先改一下代码让这个钩子先返回`null`。再看,控制台就没有错误警告了。
## 理解
现在我们也让控制台中不在有错误提醒了,那么我们来探讨第二个问题:`snapshot`值是什么,这个钩子的字面意思就是:在更新前获取`snapshot`。那么什么是`snapshot`?这个单词是快照的意思。大家在阿里云买过云服务器的可能知道,这个快照是把我们的服务器当时的一个运行状态记录下来,当我们的服务器崩溃了,或者出现了一个致命的无法修复的问题的时候,我们可以通过快照来快速将服务器恢复到创建快照的那个时间点的运行状态,有点类似时间倒流的一个操作。
那么我们组件这边更新前获取快照是不是也是这个意思呢?而且我应该将什么值作为快照值来返回呢?其实,任何值都可以是快照值,数字,字符串,对象,都行。我们来试一下:
```jsx
class Count extends React.Component {
...
getSnapshotBeforeUpdate() {
console.log("Count--getSnapshotBeforeUpdate");
// return 123;
// return {count: 123};
return "123";
}
...
}
```
![image-20220104153149979](https://file.lynchow.com/image-20220104153149979.png)
我上面这三种情况我都不会再报错了。
## `snapshot`的去向
通过前面的例子可以看出,其实这个钩子,我返回什么在语法规则以及`react`中的限制条件中都没有任何错误。但是我这个钩子到底应该返回什么才是合适的呢?而且我们返回的这个快照去哪了呢?用来干什么用呢?
我们来猜一下,`getSnapshotBeforeUpdate`钩子返回的快照去哪了?按照流程走下去的话就要调用`componentDidUpdate`钩子了,那么有没有可能是传到这个钩子里了呢?
我们之前一直也没有说过这个钩子有没有参数,我们看一下官方文档:
![image-20220104154027870](https://file.lynchow.com/image-20220104154027870.png)
什么意思?有三个参数对不对?而且第三个参数还就是`snapshot`。但是目前的情况下我们代码里虽然说写了`componentDidUpdate`钩子,但是我们接参数了吗?没接。那么我们如果在这里接了`snapshot`的话,`getSnapshotBeforeUpdate`钩子的返回值是不是就到了`componentDidUpdate`钩子里了?
那么我这里有另外一个问题。`componentDidUpdate`钩子的前两个参数是什么?我们现在代码案例中来看一下:
```jsx
class Count extends React.Component {
...
componentDidUpdate(prevProps, prevState) {
console.log("Count--componentDidUpdate",prevProps, prevState);
}
...
}
```
我们把其他代码先省略了,但是我要说一点,我在源码中是把`getSnapshotBeforeUpdate`钩子还有`getDerivedStateFromProps`钩子都注释掉的。我们来看一下这两个参数都传入了什么:
![image-20220104154729707](https://file.lynchow.com/image-20220104154729707.png)
从我们的输出结果来看,第一个是一个空对象,第二个是更新前的`state`。那么我们类比一下,`prevProps`参数应该就是更新前的`props`,但是我们渲染的时候一直也没有传`props`,所以说这里输出的一直都是空对象。
那么这个时候我们把之前那两个钩子取消注释的话会不会对功能有影响呢?不会有任何影响。那么还是看官方文档。
![image-20220104160631383](/home/jingxun/.config/Typora/typora-user-images/image-20220104160631383.png)
官方说,如果组件实现了`getSnapshotBeforeUpdate`钩子那么返回值就会传给`componentDidUpdate`钩子,那么我们在`componentDidUpdate`钩子中接一下看看能不能接到
```jsx
class Count extends React.Component {
...
componentDidUpdate(prevProps, prevState, snapshot) {
console.log("Count--componentDidUpdate", prevProps, prevState, snapshot);
}
...
}
```
![image-20220104160926822](https://file.lynchow.com/image-20220104160926822.png)
从图中可以看得出来我们成功在`componentDidUpdate`钩子中接到了这个快照值,而且确实这个快照值可以为任何值。
我们仙子啊已经是了解了`getSnapshotBeforeUpdate`钩子的一下基本情况了,那么这个钩子的应用场景什么呢?我们在下节课来通过案例再做进一步的介绍
## 总结
- `getSnapshotBeforeUpdate`钩子在`render`和`componentDidUpdate`
- `getSnapshotBeforeUpdate`钩子必须要有返回值,可以为不是`undefined`的任何值
- `getSnapshotBeforeUpdate`钩子的返回值会顺流传给`componentDidUpdate`
- `componentDidUpdate`会接收组件更新前的`snapshot`,`props`和`state`
Loading…
Cancel
Save