💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
[官方中文文档](https://zh-hans.reactjs.org/docs/hooks-intro.html) ## Hook 简介 *Hook*是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。 ``` import React, { useState } from 'react'; function Example() { // 声明一个新的叫做 “count” 的 state 变量 const [count, setCount] = useState(0); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); } ``` 在我们继续之前,请记住 Hook 是: * **完全可选的。**你无需重写任何已有代码就可以在一些组件中尝试 Hook。但是如果你不想,你不必现在就去学习或使用 Hook。 * **100% 向后兼容的。**Hook 不包含任何破坏性改动。 * **现在可用。**Hook 已发布于 v16.8.0。 Hook 为已知的 React 概念提供了更直接的 API:props, state,context,refs 以及生命周期。稍后我们将看到,Hook 还提供了一种更强大的方式来组合他们。 ## State Hook ~~~ import React, { useState } from 'react'; function Example() { // 声明一个叫 “count” 的 state 变量和一个让你更新它的函数 默认是0 const [count, setCount] = useState(0); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); } ~~~ **`useState`需要哪些参数?** `useState()`方法里面唯一的参数就是初始 state。 **`useState`方法的返回值是什么?** 返回值为:当前 state 以及更新 state 的函数。这就是我们写`const [count, setCount] = useState()`的原因。 ### 读取 State Hook 里 直接使用 变量名 count 就可以获取 state的值(class 中需要使用 this.state.count) ~~~ <p>You clicked {count} times</p> ~~~ ### 更新 State Hook 里,直接调用`setCount` 赋值 (class 里 `this.setState()`来更新`count`值) ~~~ <button onClick={() => setCount(count + 1)}> Click me </button> ~~~ ## Effect Hook 在 React 组件中执行过数据获取、订阅或者手动修改过 DOM。我们统一把这些操作称为“副作用”,或者简称为“作用”。 `useEffect`就是一个 Effect Hook,给函数组件增加了操作副作用的能力。它跟 class 组件中的`componentDidMount`、`componentDidUpdate`和`componentWillUnmount`具有相同的用途,只不过被合并成了一个 API。 ~~~ import React, { useState, useEffect } from 'react'; function Example() { const [count, setCount] = useState(0); // useEffect 相当于 componentDidMount 和 componentDidUpdate: // 组件加载以后执行 useEffect(() => { // 使用浏览器的 API 更新页面标题 document.title = `You clicked ${count} times`; }); // 这个是空数组, 只会在组件加载进入 DOM 后执行一次 useEffect(() => { // 使用浏览器的 API 更新页面标题 document.title = `You clicked ${count} times`; }, []); // 这个在每次count 变量改变都会触发, 相当于vue 里的 watch 了 count变量 useEffect(() => { // 使用浏览器的 API 更新页面标题 document.title = `You clicked ${count} times`; }, [count]); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); } ~~~ 当你调用`useEffect`时,就是在告诉 React 在完成对 DOM 的更改后运行你的“副作用”函数。由于副作用函数是在组件内声明的,所以它们可以访问到组件的 props 和 state。默认情况下,React 会在每次渲染后调用副作用函数 ——**包括**第一次渲染的时候。 跟`useState`一样,你可以在组件中多次使用`useEffect` ### 返回值 **effect可以返回一个函数** 这是 effect 可选的清除机制, 每个 effect 都可以返回一个清除函数。React 会在**组件卸载**的时候执行清除操作。这就是为什么 React*会*在执行当前 effect 之前对上一个 effect 进行清除。 ## 使用 React Hooks 的规则 Hook 就是 JavaScript 函数,但是使用它们会有两个额外的规则: * **只在最顶层调用 Hook** :**不要在循环,条件或嵌套函数中调用 Hook**,确保总是在你的 React 函数的最顶层以及任何 **return **之前调用他们。 * **只在 React 函数中调用 Hook**:**不要在普通的 JavaScript 函数中调用 Hook**。你可以: * ✅ 在 React 的函数组件中调用 Hook * ✅ 在自定义 Hook 中调用其他 Hook 遵循此规则,确保组件的状态逻辑在代码中清晰可见。 ## 自定义 Hook Hook 来订阅一个好友的在线状态。假设我们想在另一个组件里重用这个订阅逻辑。 首先,我们把这个逻辑抽取到一个叫做`useFriendStatus`的自定义 Hook 里: ~~~ import React, { useState, useEffect } from 'react'; function useFriendStatus(friendID) { const [isOnline, setIsOnline] = useState(null); function handleStatusChange(status) { setIsOnline(status.isOnline); } useEffect(() => { ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange); return () => { ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange); }; }); return isOnline; } ~~~ 它将`friendID`作为参数,并返回该好友是否在线: 现在我们可以在两个组件中使用它: ~~~ function FriendStatus(props) { const isOnline = useFriendStatus(props.friend.id); if (isOnline === null) { return 'Loading...'; } return isOnline ? 'Online' : 'Offline'; } ~~~ ~~~ function FriendListItem(props) { const isOnline = useFriendStatus(props.friend.id); return ( <li style={{ color: isOnline ? 'green' : 'black' }}> {props.friend.name} </li> ); } ~~~ 每个组件间的 state 是完全独立的。Hook 是一种复用*状态逻辑*的方式,它不复用 state 本身。事实上 Hook 的每次*调用*都有一个完全独立的 state —— 因此你可以在单个组件中多次调用同一个自定义 Hook。