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用了好一段时间,写个小总结记录下
复用业务逻辑的已有方案比如 render props 和 高阶组件,需要重新组织你的组件结构,这可能会很麻烦,使你的代码难以理解,你会发现由 providers,consumers,高阶组件,render props 等其他抽象层组成的组件会形成“嵌套地狱”
=> React 需要为共享状态逻辑提供更好的原生途径。
Hook 就是 JavaScript 函数,但是使用它们会有两个额外的规则:
hook之间相互独自
useEffect 会在每次渲染后都执行
如果你熟悉 React class 的生命周期函数,你可以把 useEffect Hook 看做 componentDidMount,componentDidUpdate 和 componentWillUnmount 这三个函数的组合。
它会在调用一个新的 effect 之前对前一个 effect 进行清理
class组件生命周期版
componentDidMount() { ChatAPI.subscribeToFriendStatus( this.props.friend.id, this.handleStatusChange ); } componentDidUpdate(prevProps) { // 取消订阅之前的 friend.id ChatAPI.unsubscribeFromFriendStatus( prevProps.friend.id, this.handleStatusChange ); // 订阅新的 friend.id ChatAPI.subscribeToFriendStatus( this.props.friend.id, this.handleStatusChange ); } componentWillUnmount() { ChatAPI.unsubscribeFromFriendStatus( this.props.friend.id, this.handleStatusChange ); }
function 组件hook版
function FriendStatus(props) { // ... useEffect(() => { // ... ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange); // 如同componentDidMount,componentDidUpdate里执行新的副作用函数 return () => { ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange); // 如同componentWillUnmount,componentDidUpdate里对已执行的副作用函数的清理函数 }; });
执行时间轴
// Mount with { friend: { id: 100 } } props ChatAPI.subscribeToFriendStatus(100, handleStatusChange); // 运行第一个 effect // Update with { friend: { id: 200 } } props ChatAPI.unsubscribeFromFriendStatus(100, handleStatusChange); // 清除上一个 effect ChatAPI.subscribeToFriendStatus(200, handleStatusChange); // 运行下一个 effect // Update with { friend: { id: 300 } } props ChatAPI.unsubscribeFromFriendStatus(200, handleStatusChange); // 清除上一个 effect ChatAPI.subscribeToFriendStatus(300, handleStatusChange); // 运行下一个 effect // Unmount ChatAPI.unsubscribeFromFriendStatus(300, handleStatusChange); // 清除最后一个 effect
也就是不管是首次render还是后面的更新render,每次render都会执行一次useEffect这个hook函数;componentDidMount 和 componentWillUnmount 是一次render,componentDidUpdate 也是一次render,所以如下图
重新render会执行新的useEffect, 执行新的useEffect之前会执行旧的useEffect的return的方法,此方法用旧的state(需要的话)。
useEffect(() => { document.title = `You clicked ${count} times`; }, [count]); // 仅在 count 更改时更新
在useEffect传第二个参数(是个array)相当于computed的作用,仅在这个参数变化时才会去执行这hook,也相当于class组件componentDidUpdate这个生命周期中比较prevState.count 和 this.state.coun不相等才执行这hook,不传就每次rerender都会执行。
如果要这个hook执行一次,那就传个[]即可
useEffect(() => { document.title = `You clicked ${count} times`; }, []); // 仅在首次render执行 只执行一次
import React, { useState } from 'react'; function Example() { // 左边第一个参数是state,右边是setState // 右边的参数是state的初始值 const [count, setCount] = useState(0); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); }
等同于
class Example extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; } render() { return ( <div> <p>You clicked {this.state.count} times</p> <button onClick={() => this.setState({ count: this.state.count + 1 })}> Click me </button> </div> ); } }
因为hook之间相互独自,所以每个state都写一个useState来生成和管理
看我写的这个demo,能看到更新一个useState,这个函数组件会rerender,但是另外一个useState的值依旧保留之前的值不受影响。
这两个之所以放一起说,是因为作用有点类似,都是用记忆计算结果来避免render的时候重新做一些计算,节省开销。不同的是,useMemo是记忆值,也就是返回值const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);;而useCallback是记忆函数,也就是返回一个函数,const memoizedCallback = useCallback(() => { doSomething(a, b); }, [a, b],);。
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
const memoizedCallback = useCallback(() => { doSomething(a, b); }, [a, b],);
而且我原以为会缓存之前多次计算过的东西,没想到测试了下,只会缓存记忆上一次的,所以只有上一次和本次的依赖值相同时,才会读取上一次的计算结果,但是上一次之前的就算有跟本次的依赖值相同的,依旧要重新计算。如下图
点击并打开控制台查看
这个可以看看这个库react-use, 里面有写了很多好用的hook
react hook 官方教程文档
react hook 官方教程视屏
hook源码分析?
The text was updated successfully, but these errors were encountered:
No branches or pull requests
hook用了好一段时间,写个小总结记录下
为什么要用hook:
复用业务逻辑的已有方案比如 render props 和 高阶组件,需要重新组织你的组件结构,这可能会很麻烦,使你的代码难以理解,你会发现由 providers,consumers,高阶组件,render props 等其他抽象层组成的组件会形成“嵌套地狱”
=> React 需要为共享状态逻辑提供更好的原生途径。
Hook 就是 JavaScript 函数,但是使用它们会有两个额外的规则:
hook之间相互独自
Effect hook:
useEffect 会在每次渲染后都执行
如果你熟悉 React class 的生命周期函数,你可以把 useEffect Hook 看做 componentDidMount,componentDidUpdate 和 componentWillUnmount 这三个函数的组合。
它会在调用一个新的 effect 之前对前一个 effect 进行清理
class组件生命周期版
function 组件hook版
执行时间轴
也就是不管是首次render还是后面的更新render,每次render都会执行一次useEffect这个hook函数;componentDidMount 和 componentWillUnmount 是一次render,componentDidUpdate 也是一次render,所以如下图
重新render会执行新的useEffect, 执行新的useEffect之前会执行旧的useEffect的return的方法,此方法用旧的state(需要的话)。
性能优化:
在useEffect传第二个参数(是个array)相当于computed的作用,仅在这个参数变化时才会去执行这hook,也相当于class组件componentDidUpdate这个生命周期中比较prevState.count 和 this.state.coun不相等才执行这hook,不传就每次rerender都会执行。
如果要这个hook执行一次,那就传个[]即可
State hook:
等同于
因为hook之间相互独自,所以每个state都写一个useState来生成和管理
看我写的这个demo,能看到更新一个useState,这个函数组件会rerender,但是另外一个useState的值依旧保留之前的值不受影响。
useMemo useCallback
这两个之所以放一起说,是因为作用有点类似,都是用记忆计算结果来避免render的时候重新做一些计算,节省开销。不同的是,useMemo是记忆值,也就是返回值
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
;而useCallback是记忆函数,也就是返回一个函数,const memoizedCallback = useCallback(() => { doSomething(a, b); }, [a, b],);
。而且我原以为会缓存之前多次计算过的东西,没想到测试了下,只会缓存记忆上一次的,所以只有上一次和本次的依赖值相同时,才会读取上一次的计算结果,但是上一次之前的就算有跟本次的依赖值相同的,依旧要重新计算。如下图
点击并打开控制台查看
写自己的hook
这个可以看看这个库react-use, 里面有写了很多好用的hook
reference
react hook 官方教程文档
react hook 官方教程视屏
todo
hook源码分析?
The text was updated successfully, but these errors were encountered: