内容简介:本文是 React 系列的第三篇
本文是 React 系列的第三篇
想阅读更多优质文章请猛戳 GitHub博客 ,一年百来篇优质文章等着你!
使用 Context Hooks
使用 Context ,首先顶层先声明 Provier
组件,并声明 value
属性,接着在后代组件中声明 Consumer
组件,这个 Consumer
子组件,只能是唯一的一个函数,函数参数即是 Context
的负载。如果有多个 Context
, Provider
和 Consumer
任意的顺序嵌套即可。
此外我们还可以针对任意一个 Context
使用 contextType
来简化对这个 Context
负载的获取。但在一个组件中,即使消费多个 Context
, contextType
也只能指向其中一个
在 Hooks 环境中,依旧可以使用 Consumer
,但是 ContextType
作为类静态成员肯定是用不了。Hooks 提供了 useContext
,不但解决了 Consumer 难用的问题同时也解决了 contextType
只能使用一个 context
的问题。
来个使用类形式的例子:
class Foo extends Component { render() { return ( <CountContext.Consumer> { count => <h1>{count}</h1> } </CountContext.Consumer> ) } } function App (props) { const [count, setCount] = useState(0); return ( <div> <button type="button" onClick={() => {setCount(count + 1) }} > Click({count}) </button> <CountContext.Provider value={count}> <Counter /> </CountContext.Provider> </div> ) }
以上就不说解释了,第一篇已经讲过了,接着将 Foo
改成用 contextType
的形式:
class Foo extends Component { static contextType = CountContext; render() { const count = this.context return ( <h1>{count}</h1> ) } }
接着使用 useContext
形式:
function Foo () { const count = useContext(CountContext) return ( <h1>{count}</h1> ) }
useContext
接收一个 context
对象(React.createContext 的返回值)并返回该 context 的当前值。当前的 context 值由上层组件中距离当前组件最近的 <CountContext.Provider>
的 value prop 决定。
当组件上层最近的 <CountContext.Provider> 更新时,该 Hook 会触发重渲染,并使用最新传递给 CountContext provider 的 context value 值。
别忘记 useContext
的参数必须是 context
对象本身:
- 正确: useContext(MyContext)
- 错误: useContext(MyContext.Consumer)
- 错误: useContext(MyContext.Provider)
调用了 useContext
的组件总会在 context
值变化时重新渲染。如果重渲染组件的开销较大,你可以 通过使用 memoization 来优化。
使用 Memo Hooks
meno 用来优化函数组件重渲染的行为,当传入属性值都不变的情况下,就不会触发组件的重渲染,否则就会触发组件重渲染。
useMemo 与 memo
meno
针对的是一个组件的渲染是否重复执行,而 useMemo
定义的是一个函数逻辑是否重复执行。
来个粟子:
function Foo (props) { return ( <h1>{props.count}</h1> ) } function App (props) { const [count, setCount] = useState(0); const double = useMemo(() => { return count * 2 }, [count]) return ( <div> <button type="button" onClick={() => {setCount(count + 1) }} > Click({count}) double: ({double}) </button> <Foo count={count}/> </div> ) }
运行结果:
如上所示, useMemo
语法与 useEffect
是一致的。第一个参数是需要执行的逻辑函数,第二个参数是这个逻辑依赖输入变量组成的数组,如果不传第二个参数,这 useMemo
的逻辑每次就会运行, useMemo
本身的意义就不存在了,所以需要传入参数。所以传入空数组就只会运行一次,策略与 useEffect
是一样的,但有一点比较大的差异就是调用时机, useEffect
执行的是副作用,所以一定是渲染之后才执行,但 useMemo
是需要返回值的,而返回值可以直接参与渲染,因此 useMemo
是在渲染期间完成的。
接下来改造一下 useMemo
,让它依赖 count
如下:
const double = useMemo(() => { return count * 2 }, [count])
接着只有当 count 变化时, useMemo
才会执行。
再次修改 useMemo, 如下:
const double = useMemo(() => { return count * 2 }, [count === 3])
现在能断定, count
在等于 3 之前,由于这个条件一直保存 false
不变,double 不会重新计算,所以一直是 0,当 count
等于 3, double
重新计算为 6,当 count
大于 3, double
在重新计算,变成 8,然后就一直保存 8 不变。
记住,传入的 useMemo
的函数会在渲染期间执行,请不要在这个函数内部执行与渲染无关的听任,诸如副作用这类操作属于 useEffect
的适用范畴,而不是 useMemo
。
你可以把 useMemo 作为性能优化的手段,但不要把它当成语义上的保证。
使用 useCallback Hooks
接下先看一下使用 memo
优化子组件的例子。
const Foo = memo (function Foo (props) { console.log('Counter render') return ( <h1>{props.count}</h1> ) }) function App (props) { const [count, setCount] = useState(0); const double = useMemo(() => { return count * 2 }, [count === 3]) return ( <div style={{padding:'100px'}}> <button type="button" onClick={() => {setCount(count + 1) }} > Click({count}) double: ({double}) </button> <Foo count={double}/> </div> ) }
使用 memo
包裹 Foo
组件,这样只有当 double
变化时, Foo
组件才会重新渲染,执行里面的 log,运行结果如下:
现在在给 Foo
中的 h1
添加一个 click
事件:
const Foo = memo (function Foo (props) { console.log('Counter render') return ( <h1 onClick={props.onClick}>{props.count}</h1> ) })
然后在 App 组件中声明 onClick 并传给 Foo
组件:
function App (props) { ... const onClick = () => { console.log('Click') } return ( <div style={{padding:'100px'}}> ... <Foo count={double} onClick={onClick}/> </div> ) }
看下运行效果:
可以看出,每次点击,不管 double
是否有变化, Foo
组件都会被渲染。那就说明每次 App 重新渲染之后, onClick
句柄的变化,导致 Foo
也被连带重新渲染了。 count
经常变化可以理解,但是 onClick
就不应该经常变化了,毕竟只是一个函数而已,所以我们要想办法让 onClick
句柄不变化。
想想我们上面讲的 useMemo
,可以这样来优化 onClick
:
const onClick = useMemo(() => { return () => { console.log('Click') } }, [])
由于我们传给 useMemo
的第二个参数是一个空数组,那么整个逻辑就只会运行一次,理论上我们返回的 onClick
就只有一个句柄。
运行效果:
现在我们把 useCallback
来实现上页 useMemo
的逻辑。
const onClick = useCallback(() => { console.log('Click') },[])
如果 useMemo
返回的是一个函数,那么可以直接使用 useCallback
来省略顶层的函数。
useCallback(fn, deps) 相当于 useMemo(() => fn, deps)
大家可能有一个疑问, useCallback
这几行代码明明每次组件渲染都会创建新的函数,它怎么就优化性能了呢。
注意,大家不要误会,使用 useCallback
确实不能阻止创建新的函数,但这个函数不一定会被返回,也就是说这个新创建的函数可能会被抛弃。 useCallback
解决的是解决的传入子组件的函数参数过多变化,导致子组件过多渲染的问题,这里需要理解好。
上述我们第二个参数传入的空数组,在实际业务并没有这么简单,至少也要更新一下状态。举个粟子:
function App (props) { ... const [clickCount, setClickCount] = useState(0); const onClick = useCallback(() => { console.log('Click') setClickCount(clickCount + 1) },[clickCount, setClickCount]) ... }
在 APP 组件中在声明一个 useState
,然后在 onClick
中调用 setClickCount
,此时 onClick 依赖 clickCount
, setClickCount
。
其实这里的 setClickCount
是不需要写的,因为 React 能保证 setState
每次返回的都是同个句柄。不信,可以看下官方文档 :
这里的场景,除了直接使用 setClickCount + 1
赋值以外, 还有一种方式甚至连 clickCount
都不用依赖。 setState
除了传入对应的 state
最新值以外,还可以传入一个函数,函数的参数即这个 state
的当前值,返回就是要更新的值:
const onClick = useCallback(() => { console.log('Click') setClickCount((clickCount) => clickCount + 1) },[])
小结
和 memo
根据属性来决定是否重新渲染组件一样, useMemo
可以根据指定的依赖不决定一段函数逻辑是否重新执行,从而优化性能。
如果 useMemo
的返回值是函数的话,那么就可以简写成 useCallback
的方式,只是简写而已,实际并没有区别。
需要特别注意的是,当依赖变化时,我们能断定 useMemo
一定重新执行。但是,即使依赖不变化我们不能假定它就一定不会重新执行,也就是说,它可以会执行,就是考虑内在优化结果。
我们可以把 useMemo
, useCallback
当做一个锦上添花优化手段,不可以过度依赖它是否重新渲染,因为 React 目前没有打包票说一定执行或者一定不执行。
交流
干货系列文章汇总如下,觉得不错点个Star,欢迎 加群 互相学习。
https://github.com/qq44924588...
我是小智,公众号「大迁世界」作者, 对前端技术保持学习爱好者。我会经常分享自己所学所看的干货 ,在进阶的路上,共勉!
关注公众号,后台回复 福利 ,即可看到福利,你懂的。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- Fetch 的实例讲解
- javaScript 常用 API 实例讲解
- C++ 运算符重载讲解与经典实例
- React 新特性 Hooks 讲解及实例(二)
- php通过pecl方式安装扩展的实例讲解
- PHP运用foreach神奇的转换数组(实例讲解)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Linux内核设计的艺术
新设计团队 / 机械工业出版社华章公司 / 2011-6-20 / 79.00元
关于Linux内核的书已经不计其数,但这本书却是独树一帜的,它的内容代表着Linux内核研究成果的世界顶尖级水平,它在世界范围内首次提出并阐述了操作系统设计的核心指导思想——主奴机制,这是所有操作系统研究者的一笔宝贵财富。本书可能也代表着同类图书的顶尖水平,是一本真正能引导我们较为容易地、极为透彻地理解Linux内核的经典之作,也可能是当前唯一能从本质上指引我们去设计和开发拥有自主知识产权的操作系......一起来看看 《Linux内核设计的艺术》 这本书的介绍吧!