Skip to content

Commit

Permalink
useState
Browse files Browse the repository at this point in the history
  • Loading branch information
wuyawei committed Sep 10, 2019
1 parent d793b33 commit 237be52
Showing 1 changed file with 46 additions and 4 deletions.
50 changes: 46 additions & 4 deletions react/深入 React hooks.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
## 前言
React Hooks的基本用法,[官方文档](https://react.docschina.org/docs/hooks-intro.html) 已经非常详细,这里我们通过一个简单的例子详细分析一些令人疑惑的问题及其背后的原理
React Hooks的基本用法,[官方文档](https://react.docschina.org/docs/hooks-intro.html) 已经非常详细,这里我们通过一个简单的例子详细分析一些令人疑惑的问题及其背后的原因

**个人博客地址 [🍹🍰 fe-code](https://github.com/wuyawei/fe-code)**

## 问题
## 示例
> 我们一起来看看这个栗子。
``` javascript
Expand Down Expand Up @@ -55,7 +55,10 @@ function Counter() {

![image.png](https://i.loli.net/2019/09/10/mYOcVkM1ASXED8a.png)

到这里我想说的到底是什么呢?我们可以清晰看见渲染到 dom 的 num 和 setInterval 中的 num,完全是不同的。这是因为对于函数式组件来讲,每次更新都会重新执行一遍渲染函数。也就是说,每次更新都会重新声明一个 `num = 0`,所以,定时器中闭包引用的那个 num,和每次更新时渲染的 num,根本不是同一个。当然,我们可以很轻易的把它们变成同一个。
## useState

### 每次都是重新执行
到这里我想说的到底是什么呢?我们可以清晰看见渲染到 dom 的 num 和 setInterval 中的 num,完全是不同的。这是因为对于函数式组件来讲,每次更新都会重新执行一遍渲染函数。也就是说,每次更新都会在当前作用域重新声明一个 `num = 0`,所以,定时器中闭包引用的那个 num,和每次更新时渲染的 num,根本不是同一个。当然,我们可以很轻易的把它们变成同一个。

``` javascript
let num = 0; // 将声明放到渲染组件外面
Expand All @@ -73,4 +76,43 @@ function Counter() {
// ...
}
```
**useState 应该理解为和普通的 javascript 函数一样,而不是 React 的什么黑魔法**。函数组件更新的时候,useState 会重新执行,对应的,也会重新声明 `[count, setCount]` 这一组常量。只不过 React 对这个函数做了一些特殊处理。比如:首次执行时,会将 useState 的参数初始化给 count,而以后再次执行时,则会直接取上次赋过的值(React 通过某种方式保存起来的)。
**useState 应该理解为和普通的 javascript 函数一样,而不是 React 的什么黑魔法**。函数组件更新的时候,useState 会重新执行,对应的,也会重新声明 `[count, setCount]` 这一组常量。只不过 React 对这个函数做了一些特殊处理。比如:首次执行时,会将 useState 的参数初始化给 count,而以后再次执行时,则会直接取上次 setCount (如果有调用) 赋过的值(React 通过某种方式保存起来的)。

有了这个概念,就不难知道,定时器里的`setCount(count + 1)` ,这个 count 和每次更新重新声明的 count,也完全是两个不同的常量,只不过它们的值,可能会相等。

### 执行图解
回过头再看一开始的例子:

``` javascript
function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
const id = setInterval(() => {
setCount(count + 1);
}, 1000);
}, []);

return <h1>{count}</h1>;
}
```

![image.png](https://i.loli.net/2019/09/10/zXIGwB2Mr7f85Pp.png)

### 小结
count 每次都被重新声明了,setInterval 因为 useEffect 设置了只执行一次的缘故,在第一次更新时闭包引用的 count 始终是 0,后续更新的 count 和它没关系。

当然,这种场景下 React 也提供了方法可以每次拿到 count 的最新值,就是给 setCount 传递一个回调函数。

``` javascript
function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
const id = setInterval(() => {
// 注意:这里变成回调了
setCount(count => count + 1);
}, 1000);
}, []);

return <h1>{count}</h1>;
}
```

0 comments on commit 237be52

Please sign in to comment.