Open coppyC opened 5 years ago
在React 的世界中,组件有两种,一种是状态组件,另一种无脑组件。 通俗来讲,状态组件就是有自己的状态this.state,而无脑组件就是不能自己控制自己,没有状态,只能通过外部的 props 来改变自己。
this.state
相信大家在第一次学习 React 组件的时候,官方的第一个示例给人留下深刻的印象,一个函数就是一个组件,从来没有见过这么简单就能创建一个组件的方式。 相比vue,创建一个组件就要去建一个 .vue 文件。 angular。。。那就更不说了,一个组件少则两个,多则三个文件。
这么说来,React 创建最小化组件的方式倒是很快捷,甚至可以在一个文件内快速创建多个组件。 但是函数创建的组件属于无脑组件,如果需要状态,就需要改装成 React.Component ,修改方式十分繁琐,而且React.Component十分不利于代码压缩。
而恰巧的是,FaceBook的程序员也更喜欢函数式组件,他们绞尽脑汁,想让函数式组件不再无脑,于是React Hook就出来了,从此,函数式组件不再无脑,它也可以有状态,如此一来,从一个无脑组件修改为状态组件也没有额外的成本。 (官方的解释: 对class的不满而有hook, https://react.docschina.org/docs/hooks-intro.html#motivation)
而且,函数式组件拥有React.Component很多没有的优点,其中,易于创建与压缩保证了开发效率与线上生产包的大小。 除了函数式组件本身的优点,还有react hook的优点,对组件更加颗粒化的代码复用,可以复用无ui部分的组件逻辑,无需封装成组件。
不得不说,React是一个开创性的框架,很多理念都极具创新。
hook 还是有点黑科技的感觉,但由于代码开源,这个技术也透明起来。 官方文档解释如下:
每个组件内部都有一个「记忆单元格」列表。它们只不过是我们用来存储一些数据的 JavaScript 对象。当你用 useState() 调用一个 Hook 的时候,它会读取当前的单元格(或在首次渲染时将其初始化),然后把指针移动到下一个。这就是多个 useState() 调用会得到各自独立的本地 state 的原因。
所以使用 hook 有着必须遵守的如下限制
其实hook最难的就是值的不稳定,js不好的同学可能会有很多bug不能理解。
react hook 在官方文档中有很多api,但实际上,最常用的就是两个useState 和 useEffect 正所谓学会20%的知识就能解决80%的问题。 甚至可以说,这两个api就可以解决所有情况,其它的api都是用来优化的。 所以学会这两个api,畅游react hook也没什么问题,但是阅读开源项目就有点吃力。
useState
useEffect
如果说有组件让react拥有灵魂,那useState就让函数式组件拥有状态 没错,这个api人如其名,就是在函数式组件中使用状态
function Example() { // 声明一个叫 “count” 的 state 变量。 const [count, setCount] = useState(0) return ( <div onClick={() => setCount(count + 1)}> {count} </div> ) }
useState的第一个参数是初始值,如果这个值是计算出来的,比较消耗性能,可以用函数返回值来优化,这样就只会在初始化时执行 init 函数
const [count, setCount] = useState(() => init(0))
使用了解构声明,第一个count就是值,对应class组件的this.state.xxx,第二个就是设置变量的函数,对应class组件的 this.setState
this.state.xxx
this.setState
ps: 实际上,我不太喜欢这个hook,因为他过于繁琐,声明了count,然后还要写一个setCount,为了保持风格一致,这个setCount 还不能拼错,拼成什么setCout什么的,毕竟声明变量也没有提示,打起来挺费劲的。(身处外包公司的我,效率天下第一)目前比较满意的就是mobx的hook,但是mobx需要包裹一层observer,也挺繁琐的,而且有时候忘了很难排错。我自己封闭了一个,写起来快捷,但也有一些约定限制或性能需要优化,目前我还没有找到一个我满意的方式来创建状态。
useState让函数组件有了状态,useEffect让函数组件有了生命周期。 有了状态,有了生命周期,嗯。。。 “ 那个,class组件,你可以下班了。 ” useEffect 是我最喜欢的一个hook,没有之一,它被设计得十分完美,一个api,承包了所有的生命周期。
举个栗子,写一个计时器
function Counter() { const [count, setCount] = useState(0) useEffect(() => { const id = setTimeout(() => setCount(count+1), 1000) return () => clearTimeout(id) }) return <div>{count}</div> }
useEffect 是 componentDidMount, componentDidUpdate, componentWillUnmount 的融合版本。参数是一个回调函数,会在componentDidMount和componentDidUpdate时执行,如果返回一个清理函数,那么下次componentDidUpdate或componentWillUnmount时,会执行这个清理函数。
这样,在组件卸载的时候,就会清理还在执行中的setTimeout,使用return的方式,让关注点融合,无需折分在两个生命周期中写,也不必在 state 中挂载setTimeoutId,妙啊~~妙啊~~
但是这里有些小问题,useEffect里面的函数是在componentDidMount这个时间点执行,也就是说,加上 unMount 到 didMount 这段时间,实际每计一秒都会超过一秒。那用setInterval啊,可是仔细想想,useEffect中包含了componentDidUpdate,想在didmount时setInterval,willunount时clear这个做法可能就办不到了。啊? 难道这个我刚才吹半天的api开始心有余力不足了? 别急。我这就来介绍它的第二个参数。
第二个参数是一个数组,传入的数组会和上一次的数组做一次浅比较,如果相同,则本次不会执行effect,如果不同则相反,一般用来做优化使用,但很多时候,我们可以传入一个空数组妙用,来保证每次比较结果都相同,从此componentDidUpdate是路人,只留下didmount和willunmount。
修改一下刚才的代码。
function Counter() { const [count, setCount] = useState(0) useEffect(() => { const id = setInterval(() => setCount(count => count + 1), 1000) return () => clearInterval(id) }, []) return <div>{count}</div> }
如此一来,就十分完美,在组件卸载是clearInterval,避免内存泄漏。 值得一提的是,不能写成这样的代码
useEffect(() => { // 不要这么写!!! const id = setInterval(() => setCount(count+1), 1000) return () => clearInterval(id) }, [])
因为count是不稳定的值,而useEffect使用了第二个参数[],导致effect中的count总是0, 而setCount可以接收一个回调函数,使得count的值是最新的。
[]
而且由于生命周期的融合,思考的方式也和之前的不一样,需要适应一下,一但适应,就会发现这个思维模式十分优雅。这种模式,也使得基于订阅的rxjs在hook中如鱼得水,虽然我不用rxjs,但还是要说一句,rxjs + hook强无敌
rxjs + hook 有多强可以看这里,强得我差点入了rxjs的坑:https://jerryzou.com/posts/rxjs-hooks
看完核心api后,其它的api可以放一边,开始diy了。
自定义hook也不是什么新的语法,就是一个函数,只是函数里面用了其它hook,所以它也就不得不成为一个新的hook,顾取名为自定义hook。React 设计巧妙的地方就在新的知识没有新的api(像之前的高阶组件),js超强,react就越强,把学习时间花在一本万利的js身上,而不是可能淘汰的react身上。
所有的hook约定使用use开关,然后接驼峰写法,官方的hook都是如此,自定义hook也要如此,没有规矩,不成方圆。
例如把之前的计时器进行封装成一个hook
function useCounter() { const [count, setCount] = useState(0) useEffect(() => { const id = setInterval(() => setCount(count => count + 1), 1000) return () => clearInterval(id) }, []) return count } function Counter() { const count = useCounter() return <div>{count}</div> }
如此一来,就复用了这个计时器的逻辑,这样再封装成别的计时器成本也不大了,比如不return div了,要span了,还要红色的
function RedCounter() { const count = useCounter() return <span style={{color: 'red'}}>{count}</span> }
说实话,官方提供的其它hook基本就是语法糖,有的甚至能用核心hook来封装。
const MyContext = React.createContext(defaultValue) function Consumer() { const value = useContext(MyContext) return <div>{value}</div> }
这个明显就是context的语法糖,懂context的一看就知道,即使没有这个语法糖,依旧可以使用MyContext.Consumer,而且如果使用第三方库来管理全局状态,像redux,mobx这些,甚至都不用context。
这也是语法糖,完全可以用 useState 自己封装一个,代码大概是这个样子
function useReducer(reducer, initialArg, init) { const initState = init ? () => init(initialArg) : initialArg const [state, setState] = useState(initState) const dispatch = (action) => setState(reducer(state, action)) return [ state, dispatch ] }
既然是可以用核心hook来shim的api,就不细讲了,至于怎么用,有兴趣看官方文档: https://react.docschina.org/docs/hooks-reference.html#usereducer
这是一个做性能优化的hook,应用场景大概是这个样子
class AnOther extends PureComponent { render() { console.log('render') return <div>another: {this.props.renderChildren()}</div> } } export default function() { const [state, setState] = useState(0) const renderChildren = () => 'children' return ( <div onClick={() => setState(state+1)}> <div>{state}</div> <AnOther renderChildren={renderChildren}></AnOther> </div> ) }
就像官方说的一样,做了优化的组件,会对props进行比较,决定是否跳过渲染来达成优化,像上面的AnOther就是做了优化的组件,如果renderChildren一样,则会路过更新。但像上面renderChildren,每次传的函数都不是同一个,使得AnOther无法做优化,表现为每次点击,AnOther都会打印 console.log('render')。这时就可以使用 useCallback来做优化,将const renderChildren = () => 'another'改为
console.log('render')
const renderChildren = () => 'another'
const renderChildren = useCallback(() => 'children', [])
这样可以保证renderChildren的引用一致,帮助AnOther完成优化。 这里useCallback第二个参数和useEffect的第二个一致,区别就是useCallback的第二个参数是必填参数。
但恕我直言,这是一个没有什么用的hook,因为在多时候,我们不知道哪些组件是有做优化的,是怎么优化的。js不好的也很难理解为什么一样功能的函数,引用会不一样,而且乱用可以还会降低性能,毕竟执行了一些没有必要的代码。还有就是第二个参数要填什么,有时候函数修改但忘记修改第二个参数,锁住了不稳定的变量,引发莫名bug。可能就会出现弊大于利的情况。
另外,这个函数也是可以使用核心hook来造轮子的,有兴趣的可以自己试试。
这又是一个性能优化的函数,类比计算属性功能,直接拿官方的例子说事
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b])
当a和b一样,computeExpensiveValue函数就不会执行,而是直接返回上一次计算的值,大致性能优化
值得一提的是,useCallback(fn, deps) 相当于 useMemo(() => fn, deps)
useCallback(fn, deps)
useMemo(() => fn, deps)
既然useCallback可以造轮子,useMemo也是可以用核心hook来造,有兴趣的课后自己实践一下。
看名字就知道是ref的hook,使用方法如下 (也没什么好说的,我就直接贴官方实例了)。
function TextInputWithFocusButton() { const inputEl = useRef(null); const onButtonClick = () => { // `current` 指向已挂载到 DOM 上的文本输入元素 inputEl.current.focus(); }; return ( <> <input ref={inputEl} type="text" /> <button onClick={onButtonClick}>Focus the input</button> </> ); }
但其实useRef是一个稳定的值,它的用法不止是ref,你可以用它来放任何东西,像这样
export default function() { const count = useRef('') return ( <input type="text" onChange={e => count.current = e.target.value} /> ) }
值得注意的是,修改 ref.current 不会触发组件的更新,这对一些场景来说很实用,像非受控组件。
另外,这个hook也可以造轮子 (果然是万能的useState),代码也不多,而且很简单,我就现场造一个
function useRef(current) { const [state] = useState({ current }) return state }
因为没有返回 setState 的关系,所以修改current 组件不会更新也就很好理解了
此hook 弥补了函数组件没有自己的ref的缺点,但使用过程极其繁琐,个人十分不喜欢,所以也没有细究,就直接贴官方文档
useImperativeHandle(ref, createHandle, [deps])
useImperativeHandle 可以让你在使用 ref 时自定义暴露给父组件的实例值。在大多数情况下,应当避免使用 ref 这样的命令式代码。useImperativeHandle 应当与 forwardRef 一起使用
const FancyInput = React.forwardRef((props, ref) => { const inputRef = useRef(); useImperativeHandle(ref, () => ({ focus: () => { inputRef.current.focus(); } })); return <input ref={inputRef} ... />; });
在本例中,渲染 的父组件可以调用 fancyInputRef.current.focus()。
这里面还用了恶心的高阶组件, 期待官方能有更好的方式使用函数组件ref。 另外,ref这种模式我觉得都是迫不得已,其实可以设计更好的组件来避免ref的使用
这是一个 功能类似 useEffect 的组件,参数也一致,唯一的区别就是effect 的执行时机,useLayoutEffect会在所有的 DOM 变更之后同步调用 effect ,调用阶段和componentDidMount, componentDidUpdate一致,而useEffect会在DOM 变更后异步调用。不能理解的话,就使用useEffect就可以了,它是异步的,不会阻塞视觉更新,当你需要用到useLayoutEffect的时候,你自然会知道这两者的区别。
例如,我写了一个库,就用 useLayoutEffect 取代 useEffect,避免dom更新后,css还没更新的尴尬情况,就是这个库 https://github.com/style-hook/style-hook (下期我再好好吹吹这个库[#滑稽])
这是一个生产环境用不上的hook,功能就像它的名字一样,debug value。 可用于在 React 开发者工具中显示自定义 hook 的标签。 记住,是只对自定义hook有效,举个栗子,就拿上面的计时器hook来说,为了方便查看,我把代码也贴上
function useCounter() { const [count, setCount] = useState(0) useEffect(() => { let count = 0 const id = setInterval(() => setCount(++count), 1000) return () => clearInterval(id) }, []) return count }
在React 开发者工具中显示如下(笔者使用的是chrome 插件) 展开标签后效果 你可能想在未展开标签时显示 count 的值,这时,你可以这么做
function useCounter() { const [count, setCount] = useState(0) useEffect(() => { let count = 0 const id = setInterval(() => setCount(++count), 1000) return () => clearInterval(id) }, []) useDebugValue(count) return count }
效果 展开标签
如果要显示的值需要经过复杂的计算,为了避免阻塞ui,可以使用第二个参数来延迟格式化 debug 值
useDebugValue(value, value => ( value / 10 * 24 * 60 * 60 * 1000 )>> 3)
但其实需要这个hook一般都是在开发环境使用,既然是开发环境,性能比生产环境差些也无可厚非。
看到这里,恭喜,hook已经学完了,但你可能还有很多疑问,别急, 官方文档的FAQ很完整,并且通俗易懂,我就不丢人献眼了。 https://react.docschina.org/docs/hooks-faq.html
或者可以在这里留言,交流有关hook的问题。
Hook好用不好用我不知道,mobx倒是比redux好用一百倍
mobx虽好用,但不可贪杯。
大师牛逼
大湿牛逼
Why React Hook?
在React 的世界中,组件有两种,一种是状态组件,另一种无脑组件。 通俗来讲,状态组件就是有自己的状态
this.state
,而无脑组件就是不能自己控制自己,没有状态,只能通过外部的 props 来改变自己。相信大家在第一次学习 React 组件的时候,官方的第一个示例给人留下深刻的印象,一个函数就是一个组件,从来没有见过这么简单就能创建一个组件的方式。 相比vue,创建一个组件就要去建一个 .vue 文件。 angular。。。那就更不说了,一个组件少则两个,多则三个文件。
这么说来,React 创建最小化组件的方式倒是很快捷,甚至可以在一个文件内快速创建多个组件。 但是函数创建的组件属于无脑组件,如果需要状态,就需要改装成 React.Component ,修改方式十分繁琐,而且React.Component十分不利于代码压缩。
而恰巧的是,FaceBook的程序员也更喜欢函数式组件,他们绞尽脑汁,想让函数式组件不再无脑,于是React Hook就出来了,从此,函数式组件不再无脑,它也可以有状态,如此一来,从一个无脑组件修改为状态组件也没有额外的成本。 (官方的解释: 对class的不满而有hook, https://react.docschina.org/docs/hooks-intro.html#motivation)
而且,函数式组件拥有React.Component很多没有的优点,其中,易于创建与压缩保证了开发效率与线上生产包的大小。 除了函数式组件本身的优点,还有react hook的优点,对组件更加颗粒化的代码复用,可以复用无ui部分的组件逻辑,无需封装成组件。
不得不说,React是一个开创性的框架,很多理念都极具创新。
hook 的使用
hook 还是有点黑科技的感觉,但由于代码开源,这个技术也透明起来。 官方文档解释如下:
所以使用 hook 有着必须遵守的如下限制
其实hook最难的就是值的不稳定,js不好的同学可能会有很多bug不能理解。
核心 hook (重点学习,敲黑板)
react hook 在官方文档中有很多api,但实际上,最常用的就是两个
useState
和useEffect
正所谓学会20%的知识就能解决80%的问题。 甚至可以说,这两个api就可以解决所有情况,其它的api都是用来优化的。 所以学会这两个api,畅游react hook也没什么问题,但是阅读开源项目就有点吃力。useState
如果说有组件让react拥有灵魂,那useState就让函数式组件拥有状态 没错,这个api人如其名,就是在函数式组件中使用状态
useState的第一个参数是初始值,如果这个值是计算出来的,比较消耗性能,可以用函数返回值来优化,这样就只会在初始化时执行 init 函数
使用了解构声明,第一个count就是值,对应class组件的
this.state.xxx
,第二个就是设置变量的函数,对应class组件的this.setState
ps: 实际上,我不太喜欢这个hook,因为他过于繁琐,声明了count,然后还要写一个setCount,为了保持风格一致,这个setCount 还不能拼错,拼成什么setCout什么的,毕竟声明变量也没有提示,打起来挺费劲的。(身处外包公司的我,效率天下第一)目前比较满意的就是mobx的hook,但是mobx需要包裹一层observer,也挺繁琐的,而且有时候忘了很难排错。我自己封闭了一个,写起来快捷,但也有一些约定限制或性能需要优化,目前我还没有找到一个我满意的方式来创建状态。
useEffect
useState让函数组件有了状态,useEffect让函数组件有了生命周期。 有了状态,有了生命周期,嗯。。。 “ 那个,class组件,你可以下班了。 ” useEffect 是我最喜欢的一个hook,没有之一,它被设计得十分完美,一个api,承包了所有的生命周期。
举个栗子,写一个计时器
useEffect 是 componentDidMount, componentDidUpdate, componentWillUnmount 的融合版本。参数是一个回调函数,会在componentDidMount和componentDidUpdate时执行,如果返回一个清理函数,那么下次componentDidUpdate或componentWillUnmount时,会执行这个清理函数。
这样,在组件卸载的时候,就会清理还在执行中的setTimeout,使用return的方式,让关注点融合,无需折分在两个生命周期中写,也不必在 state 中挂载setTimeoutId,妙啊~~妙啊~~
但是这里有些小问题,useEffect里面的函数是在componentDidMount这个时间点执行,也就是说,加上 unMount 到 didMount 这段时间,实际每计一秒都会超过一秒。那用setInterval啊,可是仔细想想,useEffect中包含了componentDidUpdate,想在didmount时setInterval,willunount时clear这个做法可能就办不到了。啊? 难道这个我刚才吹半天的api开始心有余力不足了? 别急。我这就来介绍它的第二个参数。
第二个参数是一个数组,传入的数组会和上一次的数组做一次浅比较,如果相同,则本次不会执行effect,如果不同则相反,一般用来做优化使用,但很多时候,我们可以传入一个空数组妙用,来保证每次比较结果都相同,从此componentDidUpdate是路人,只留下didmount和willunmount。
修改一下刚才的代码。
如此一来,就十分完美,在组件卸载是clearInterval,避免内存泄漏。 值得一提的是,不能写成这样的代码
因为count是不稳定的值,而useEffect使用了第二个参数
[]
,导致effect中的count总是0, 而setCount可以接收一个回调函数,使得count的值是最新的。而且由于生命周期的融合,思考的方式也和之前的不一样,需要适应一下,一但适应,就会发现这个思维模式十分优雅。这种模式,也使得基于订阅的rxjs在hook中如鱼得水,虽然我不用rxjs,但还是要说一句,rxjs + hook强无敌
rxjs + hook 有多强可以看这里,强得我差点入了rxjs的坑:https://jerryzou.com/posts/rxjs-hooks
自定义 hook
看完核心api后,其它的api可以放一边,开始diy了。
自定义hook也不是什么新的语法,就是一个函数,只是函数里面用了其它hook,所以它也就不得不成为一个新的hook,顾取名为自定义hook。React 设计巧妙的地方就在新的知识没有新的api(像之前的高阶组件),js超强,react就越强,把学习时间花在一本万利的js身上,而不是可能淘汰的react身上。
约定
所有的hook约定使用use开关,然后接驼峰写法,官方的hook都是如此,自定义hook也要如此,没有规矩,不成方圆。
实战
例如把之前的计时器进行封装成一个hook
如此一来,就复用了这个计时器的逻辑,这样再封装成别的计时器成本也不大了,比如不return div了,要span了,还要红色的
其它hook
说实话,官方提供的其它hook基本就是语法糖,有的甚至能用核心hook来封装。
useContext
这个明显就是context的语法糖,懂context的一看就知道,即使没有这个语法糖,依旧可以使用MyContext.Consumer,而且如果使用第三方库来管理全局状态,像redux,mobx这些,甚至都不用context。
useReducer
这也是语法糖,完全可以用 useState 自己封装一个,代码大概是这个样子
既然是可以用核心hook来shim的api,就不细讲了,至于怎么用,有兴趣看官方文档: https://react.docschina.org/docs/hooks-reference.html#usereducer
useCallback
这是一个做性能优化的hook,应用场景大概是这个样子
就像官方说的一样,做了优化的组件,会对props进行比较,决定是否跳过渲染来达成优化,像上面的AnOther就是做了优化的组件,如果renderChildren一样,则会路过更新。但像上面renderChildren,每次传的函数都不是同一个,使得AnOther无法做优化,表现为每次点击,AnOther都会打印
console.log('render')
。这时就可以使用 useCallback来做优化,将const renderChildren = () => 'another'
改为这样可以保证renderChildren的引用一致,帮助AnOther完成优化。 这里useCallback第二个参数和useEffect的第二个一致,区别就是useCallback的第二个参数是必填参数。
但恕我直言,这是一个没有什么用的hook,因为在多时候,我们不知道哪些组件是有做优化的,是怎么优化的。js不好的也很难理解为什么一样功能的函数,引用会不一样,而且乱用可以还会降低性能,毕竟执行了一些没有必要的代码。还有就是第二个参数要填什么,有时候函数修改但忘记修改第二个参数,锁住了不稳定的变量,引发莫名bug。可能就会出现弊大于利的情况。
另外,这个函数也是可以使用核心hook来造轮子的,有兴趣的可以自己试试。
useMemo
这又是一个性能优化的函数,类比计算属性功能,直接拿官方的例子说事
当a和b一样,computeExpensiveValue函数就不会执行,而是直接返回上一次计算的值,大致性能优化
值得一提的是,
useCallback(fn, deps)
相当于useMemo(() => fn, deps)
既然useCallback可以造轮子,useMemo也是可以用核心hook来造,有兴趣的课后自己实践一下。
useRef
看名字就知道是ref的hook,使用方法如下 (也没什么好说的,我就直接贴官方实例了)。
但其实useRef是一个稳定的值,它的用法不止是ref,你可以用它来放任何东西,像这样
值得注意的是,修改 ref.current 不会触发组件的更新,这对一些场景来说很实用,像非受控组件。
另外,这个hook也可以造轮子 (果然是万能的useState),代码也不多,而且很简单,我就现场造一个
因为没有返回 setState 的关系,所以修改current 组件不会更新也就很好理解了
useImperativeHandle
此hook 弥补了函数组件没有自己的ref的缺点,但使用过程极其繁琐,个人十分不喜欢,所以也没有细究,就直接贴官方文档
useImperativeHandle 可以让你在使用 ref 时自定义暴露给父组件的实例值。在大多数情况下,应当避免使用 ref 这样的命令式代码。useImperativeHandle 应当与 forwardRef 一起使用
在本例中,渲染 的父组件可以调用 fancyInputRef.current.focus()。
这里面还用了恶心的高阶组件, 期待官方能有更好的方式使用函数组件ref。 另外,ref这种模式我觉得都是迫不得已,其实可以设计更好的组件来避免ref的使用
useLayoutEffect
这是一个 功能类似 useEffect 的组件,参数也一致,唯一的区别就是effect 的执行时机,useLayoutEffect会在所有的 DOM 变更之后同步调用 effect ,调用阶段和componentDidMount, componentDidUpdate一致,而useEffect会在DOM 变更后异步调用。不能理解的话,就使用useEffect就可以了,它是异步的,不会阻塞视觉更新,当你需要用到useLayoutEffect的时候,你自然会知道这两者的区别。
例如,我写了一个库,就用 useLayoutEffect 取代 useEffect,避免dom更新后,css还没更新的尴尬情况,就是这个库 https://github.com/style-hook/style-hook (下期我再好好吹吹这个库[#滑稽])
useDebugValue
这是一个生产环境用不上的hook,功能就像它的名字一样,debug value。 可用于在 React 开发者工具中显示自定义 hook 的标签。 记住,是只对自定义hook有效,举个栗子,就拿上面的计时器hook来说,为了方便查看,我把代码也贴上
在React 开发者工具中显示如下(笔者使用的是chrome 插件) 展开标签后效果 你可能想在未展开标签时显示 count 的值,这时,你可以这么做
效果 展开标签
如果要显示的值需要经过复杂的计算,为了避免阻塞ui,可以使用第二个参数来延迟格式化 debug 值
但其实需要这个hook一般都是在开发环境使用,既然是开发环境,性能比生产环境差些也无可厚非。
hook F&Q
看到这里,恭喜,hook已经学完了,但你可能还有很多疑问,别急, 官方文档的FAQ很完整,并且通俗易懂,我就不丢人献眼了。 https://react.docschina.org/docs/hooks-faq.html
或者可以在这里留言,交流有关hook的问题。