创建
function App() { // 普通函数return (<div>1</div>);}const App = () => { // 箭头函数return (<div>1</div>)}const App = () => (<div>1</div>) // 简写
生命周期:Effect Hook
Effect Hook:副作用钩子。
通过使用这个 Hook,你可以告诉 React 组件需要在渲染后执行某些操作。React 会保存你传递的函数(我们将它称之为 “effect”),并且在执行 DOM 更新之后调用它。在这个 effect 中,我们设置了 document 的 title 属性,不过我们也可以执行数据获取或调用其他命令式的 API。
为什么在组件内部调用
useEffect?将
useEffect放在组件内部让我们可以在 effect 中直接访问countstate 变量(或其他 props)。我们不需要特殊的 API 来读取它 —— 它已经保存在函数作用域中。Hook 使用了 JavaScript 的闭包机制,而不用在 JavaScript 已经提供了解决方案的情况下,还引入特定的 React API。useEffect 对应类组件中的生命周期
```javascript useEffect( () => {console.log(1)},[] ) ===== componentDidMount // 只在挂载时触发
useEffect( () => {console.log(1)},[n] ) ===== componentDidUpdate
// 第一次也会执行,只在 n 更新时更新,不写表示监听 state props
useEffect( () => { ===== componentWillUnmount // 组件消亡时触发 console.log(1) return () => {} } )
<a name="R4pc0"></a># 性能优化**[stale closure(旧的闭包) ](https://dmitripavlutin.com/react-hooks-stale-closures/)- 在 setInterval 中使用 setState 时,因为闭包产生的 bug**<a name="sYMzL"></a>### 如果 effect 的依赖频繁变化,该怎么办?- 有时候,你的 effect 可能会使用一些频繁变化的值。你可能会忽略依赖列表中 state,但这通常会引起 Bug:```javascriptfunction Counter() {const [count, setCount] = useState(0);useEffect(() => {const id = setInterval(() => {setCount(count + 1); // 这个 effect 依赖于 `count` state }, 1000);return () => clearInterval(id);}, []); // 🔴 Bug: `count` 没有被指定为依赖return <h1>{count}</h1>;}
- 传入空的依赖数组
[],意味着该 hook 只在组件挂载时运行一次,并非重新渲染时。但如此会有问题,在setInterval的回调中,count的值不会发生变化。因为当 effect 执行时,我们会创建一个闭包,并将count的值被保存在该闭包当中,且初值为0。每隔一秒,回调就会执行setCount(0 + 1),因此,count永远不会超过 1。 指定
[count]作为依赖列表就能修复这个 Bug,但会导致每次改变发生时定时器都被重置。事实上,每个setInterval在被清除前(类似于setTimeout)都会调用一次。但这并不是我们想要的。要解决这个问题,我们可以使用setState的函数式更新形式。它允许我们指定 state 该 如何 改变而不用引用state。function Counter() {const [count, setCount] = useState(0);useEffect(() => {const id = setInterval(() => {setCount(c => c + 1); // ✅ 在这不依赖于外部的 `count` 变量 }, 1000);return () => clearInterval(id);}, []); // ✅ 我们的 effect 不使用组件作用域中的任何变量return <h1>{count}</h1>;}
(
setCount函数的身份是被确保稳定的,所以可以放心的省略掉)
此时,setInterval的回调依旧每秒调用一次,但每次setCount内部的回调取到的count是最新值(在回调中变量命名为c)。自定义 Hook
挂载时不执行,只在数据更新时执行
function useUpdate(fn, array) {const [count, setCount] = useState(0)useEffect(() => {setCount(x => x + 1)}, array)useEffect(() => {if (count > 1) {fn()}}, [count])}
