We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Hook 是 React 16.8 的新增特性,可以让你在不编写 class 的情况使用 state 以及其他的 React 特性。
React Hooks出现,组件可尽量写成纯函数,如需要外部功能和副作用,就用钩子把外部代码"钩"进来。 React Hooks 就是那些钩子。
使用 React Hooks 好处:
React 默认提供了一些常用钩子,也可以封装自己的钩子,以下常用的几个钩子:
useState() useEffect() useCallback() useMemo() useContext() useReducer()
useState()用于为函数组件引入状态(state)。纯函数不能有状态,所以把状态放在钩子里面。
useState()
useState() 方法里面唯一的参数就是初始 state。不同于 class 的是,我们可以按照需要使用数字或字符串对其进行赋值,而不一定是对象。
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> ); }
注意 useState() 我们建议使用多个 state 变量 在有关联的情况下,State 变量可使用对象和数组,但注意更新 state,变更需给定新对象或数组,若改变原始对象或数组则不会触发钩子。
注意
Effect Hook 可以让你在函数组件中执行副作用操作
可以把 useEffect Hook 看做 componentDidMount,componentDidUpdate 和 componentWillUnmount 这三个函数的组合
useEffect
componentDidMount
componentDidUpdate
componentWillUnmount
在 React 组件中有两种常见副作用操作:需要清除的和不需要清除的。React 的 class 组件中,会把副作用操作放到 componentDidMount 和 componentDidUpdate 函数中,并在 componentWillUnmount 中清除它。
class 组件中,把副作用操作放到 componentDidMount 和 componentDidUpdate 函数中:
class Example extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; } componentDidMount() { document.title = `You clicked ${this.state.count} times`; } componentDidUpdate() { document.title = `You clicked ${this.state.count} times`; } render() { return ( <div> <p>You clicked {this.state.count} times</p> <button onClick={() => this.setState({ count: this.state.count + 1 })}> Click me </button> </div> ); } }
useEffect 改写:
import React, { useState, useEffect } from 'react'; function Example() { const [count, setCount] = useState(0); useEffect(() => { document.title = `You clicked ${count} times`; }); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); }
在 React class 中,把副作用操作放到 componentDidMount 和 componentDidUpdate 函数中,并在 componentWillUnmount 中清除它。
class Example extends React.Component { constructor(props) { super(props); } componentDidMount() { window.addEventListener('scroll', callback) } componentWillUnmount() { window.removeEventListener('scroll', callback) } render() { return ( <div/> ); } }
import React, { useEffect } from 'react'; function Example() { useEffect(() => { window.addEventListener('scroll', callback)` return () => window.removeEventListener('scroll', callback) }) return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ) }
export const useWindowEvent = (event, callback, dependencies) => { useEffect(() => { window.addEventListener(event, callback); return () => window.removeEventListener(event, callback); }, [event, callback, ...dependencies]); };
useCallback 返回一个 memoized 回调函数。
useCallback
把内联回调函数及依赖项数组作为参数传入 useCallback,它将返回该回调函数的 memoized 版本,该回调函数仅在某个依赖项改变时才会更新。当你把回调函数传递给经过优化的并使用引用相等性去避免非必要渲染(例如 shouldComponentUpdate)的子组件时,它将非常有用。
shouldComponentUpdate
const memoizedCallback = useCallback( () => { doSomething(a, b); }, [a, b], );
useCallback(fn, deps) 相当于 useMemo(() => fn, deps)。
useCallback(fn, deps)
useMemo(() => fn, deps)
useCallback(fn, deps) 请求数据场景缓存
useMemo 返回一个 memoized 值。
useMemo
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
把“创建”函数和依赖项数组作为参数传入 useMemo,它仅会在某个依赖项改变时才重新计算 memoized 值。如果没有提供依赖项数组,useMemo 在每次渲染时都会计算新的值。这种优化有助于避免在每次渲染时都进行高开销的计算。
useCallback 和 useMemo 都可缓存函数的引用或值,但是从更细的使用角度来说 useCallback 缓存函数的引用,useMemo 缓存计算数据的值。 useMemo 更多用于复杂的运算。
const AppContext = useContext(AppContextProps)
接收一个 context 对象(React.createContext 的返回值)并返回该 context 的当前值。当前的 context 值由上层组件中距离当前组件最近的 <AppContext.Provider> 的 value prop 决定。
React.createContext
<AppContext.Provider>
value
当组件上层最近的 <AppContext.Provider> 更新时,该 Hook 会触发重渲染,并使用最新传递给 AppContext provider 的 context value 值。
AppContext
useContext 的参数必须是 context 对象本身:
useContext
useContext(AppContext)
export const AppContext = React.createContext<Partial<AppContextProps>>({}) <AppContext.Provider value={{ authenticated: state.authenticated, userInfo: state.userInfo, }} > {props.children} </AppContext.Provider> import { AppContext } from '../AppContext' function ThemedButton() { const Context = useContext(AppContext); return ( <div> {Context.userInfo} </div> ); }
Hook 本质就是 JavaScript 函数,但是在使用它时需要遵循两条规则, linter 插件 可强制执行这些规则:
不要在循环,条件或嵌套函数中调用 Hook,确保总是在你的 React 函数的最顶层调用他们。遵守这条规则,你就能确保 Hook 在每一次渲染中都按照同样的顺序被调用。这让 React 能够在多次的 useState 和 useEffect 调用之间保持 hook 状态的正确。
useState
不要在普通的 JavaScript 函数中调用 Hook。你可以:
遵循此规则,确保组件的状态逻辑在代码中清晰可见。
npm install eslint-plugin-react-hooks --save-dev // ESLint 配置 { "plugins": [ // ... "react-hooks" ], "rules": { // ... "react-hooks/rules-of-hooks": "error", // 检查 Hook 的规则 "react-hooks/exhaustive-deps": "warn" // 检查 effect 的依赖 } }
React Hook Intro
Creating a Reusable Window Event Listener Hook with useEffect and useCallback
React Hooks 原理
react-use
useApolloClient
React Hooks 你真的用对了吗?
useCallback、useMemo 分析 & 差别
The text was updated successfully, but these errors were encountered:
No branches or pull requests
Hook 是 React 16.8 的新增特性,可以让你在不编写 class 的情况使用 state 以及其他的 React 特性。
React Hooks出现,组件可尽量写成纯函数,如需要外部功能和副作用,就用钩子把外部代码"钩"进来。 React Hooks 就是那些钩子。
使用 React Hooks 好处:
React 默认提供了一些常用钩子,也可以封装自己的钩子,以下常用的几个钩子:
useState():状态钩子
useState()
用于为函数组件引入状态(state)。纯函数不能有状态,所以把状态放在钩子里面。useState()
方法里面唯一的参数就是初始 state。不同于 class 的是,我们可以按照需要使用数字或字符串对其进行赋值,而不一定是对象。useEffect():副作用钩子
Effect Hook 可以让你在函数组件中执行副作用操作
在 React 组件中有两种常见副作用操作:需要清除的和不需要清除的。React 的 class 组件中,会把副作用操作放到
componentDidMount
和componentDidUpdate
函数中,并在componentWillUnmount
中清除它。无需清除的 effect
class 组件中,把副作用操作放到
componentDidMount
和componentDidUpdate
函数中:useEffect 改写:
需清除的 effect
在 React class 中,把副作用操作放到
componentDidMount
和componentDidUpdate
函数中,并在componentWillUnmount
中清除它。useEffect 改写:
Window Event Listener Hook 类似场景
useCallback()
useCallback
返回一个 memoized 回调函数。把内联回调函数及依赖项数组作为参数传入
useCallback
,它将返回该回调函数的 memoized 版本,该回调函数仅在某个依赖项改变时才会更新。当你把回调函数传递给经过优化的并使用引用相等性去避免非必要渲染(例如shouldComponentUpdate
)的子组件时,它将非常有用。useCallback(fn, deps)
相当于useMemo(() => fn, deps)
。useMemo()
useMemo
返回一个 memoized 值。把“创建”函数和依赖项数组作为参数传入 useMemo,它仅会在某个依赖项改变时才重新计算 memoized 值。如果没有提供依赖项数组,useMemo 在每次渲染时都会计算新的值。这种优化有助于避免在每次渲染时都进行高开销的计算。
useContext()
接收一个 context 对象(
React.createContext
的返回值)并返回该 context 的当前值。当前的 context 值由上层组件中距离当前组件最近的<AppContext.Provider>
的value
prop 决定。当组件上层最近的
<AppContext.Provider>
更新时,该 Hook 会触发重渲染,并使用最新传递给AppContext
provider 的 contextvalue
值。useContext
的参数必须是 context 对象本身:useContext(AppContext)
Hook 规则
Hook 本质就是 JavaScript 函数,但是在使用它时需要遵循两条规则, linter 插件 可强制执行这些规则:
不要在循环,条件或嵌套函数中调用 Hook,确保总是在你的 React 函数的最顶层调用他们。遵守这条规则,你就能确保 Hook 在每一次渲染中都按照同样的顺序被调用。这让 React 能够在多次的
useState
和useEffect
调用之间保持 hook 状态的正确。不要在普通的 JavaScript 函数中调用 Hook。你可以:
遵循此规则,确保组件的状态逻辑在代码中清晰可见。
Other Resources
React Hook Intro
Creating a Reusable Window Event Listener Hook with useEffect and useCallback
React Hooks 原理
react-use
useApolloClient
React Hooks 你真的用对了吗?
useCallback、useMemo 分析 & 差别
The text was updated successfully, but these errors were encountered: