Created
September 25, 2019 10:22
-
-
Save hacker0limbo/f62f2bd6b9e6b158f8c345e63341d569 to your computer and use it in GitHub Desktop.
Revisions
-
hacker0limbo created this gist
Sep 25, 2019 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,93 @@ 两个计数器代码: 使用 class: ```javascript import React, {Component} from "react"; import ReactDOM from "react-dom"; class Example extends Component { state = { count: 0 }; componentDidMount() { setTimeout(() => { console.log(`You clicked ${this.state.count} times`); }, 3000); } componentDidUpdate() { setTimeout(() => { console.log(`You clicked ${this.state.count} times`); }, 3000); } render() { return ( <div> <p>You clicked {this.state.count} times</p> <button onClick={() => this.setState({ count: this.state.count + 1 })}> Click me </button> </div> ) } } const rootElement = document.getElementById("root"); ReactDOM.render(<Example />, rootElement); ``` 使用 hook: ```javascript import React, {useState, useEffect} from "react"; import ReactDOM from "react-dom"; function Example() { const [count, setCount] = useState(0); useEffect(() => { setTimeout(() => { console.log(`You clicked ${count} times`); }, 3000); }); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(prevCount => prevCount + 1)}> Click me </button> </div> ); } const rootElement = document.getElementById("root"); ReactDOM.render(<Example />, rootElement); ``` 操作: 连续点击 5 次增加按钮: - hook 的组件 timeout 以后依次显示 1, 2, 3, 4, 5 - class 的组件 timeout 以后依次显示 5, 5, 5, 5, 5 ### 原因 由于函数组件使用闭包的特点, 每一次调用`useEffect()`函数, 里面的 count 都是当前的 state, 相当于渲染 5 次, 每次都是一份快照, 里面的 state 也是独立的, 因此最后的结果也是符合直觉 class 组件在每次 state 更新重新渲染以后, 都会去修改 `this.props`或者`this.state`, 这样永远都是拿到的最新的 state 或者 props 对于函数式组件, 如果想要获取 state 的最新值, 需要使用 ref 同时, 函数式组件里面, 例如使用`setCount(count+1)`这种, 这里的`count`永远都是一个**值**, 因此尽量使用`setCount(prevCount => prevCount+1)`这种写法进行 state 更新, 如下的例子设置 state 永远只会设置一次, 例如: ```javascript setCount(count+1) setCount(count+1) ``` 由于闭包的原因, 这里相当于: ```javascript setCount(2) setCount(2) ``` **关于`useEffect`**: 最后, 如果一个函数有使用到 props 或者 state, 那么这个函数会参与到数据流中, 两种办法: - 使用`useCallback`包裹, 当然其中的 dependency array 里需要包含该函数访问到的组件里的 props 和 state - 直接将该函数放入`useEffect`中, dependency array 里面同样需要包含该函数访问到的 props 和 state