写在开头
- 阅读之前:希望您知道基础hooks的使用,如useCallback,useReducer等,我并不会过多的介绍文章中出现的hooks。
- 注释的问题:为了表达的更清楚,在有的React代码片段中,我会添加注释来解释一些东西,为了方便书写,在jsx中我使用的是//而不是{ /* */ },请忽略这个错误。
从一个简单的useToggle开始
相信大家都使用过复选框或者开关组件,我们实现一个useToggle()
让事情变的更简单
function App() {
const [on, toggle] = useToggle();
//on是状态,toggle切换状态
...
}
简单实现
import React from 'react';
export function useToggle(on: boolean): [boolean, () => void] {
const [_on, setOn] = React.useState(on);
return [_on, () => {
setOn(!_on)}]
}
现在这个useToggle已经可以投入使用了,有一个小问题不知道各位观察到没有?每次on状态的改变,都会导致我们重新返回新的toggle方法,当然简单使用的话其实并没有什么影响。
尝试优化useToggle
现在我们有了新的需求,尝试优化一下useToggle来实现它。
例如:
function App() {
const [on, toggle] = useToggle();
return(
<div>
//NeedOn仅需要使用on状态
<NeedOn on ={
on}></NeedOn>
//Button组件仅负责修改on的状态
<Button toggle = {
toggle}></Button>
</div>
)
}
在上面的例子中,我们有两个组件,NeedOn仅需要使用on状态,Button仅负责修改on的状态。
而现在每一次on的改变都会引起App的重新渲染,进而导致NeedOn
和Button
的重新渲染。现在我们需要在功能不变的情况下使on改变时,Button
不再重新渲染。
如何解决呢?首先我们要解决toggle改变的问题,因为一个组件不在重新渲染的基础条件之一就是它的props不再改变。我们可以使用useCallback()来解决这个问题。
import React from 'react';
export function useToggle(on: boolean): [boolean, () => void] {
const [_on, setOn] = React.useState(on);
const _toggle = React.useCallback(() => {
setOn(!_on);
},[])
return [_on,_toggle];
}
//现在我们使用了useCallback来缓存_toggle。
//由于传入数组为空_toggle再也不会被更新了,现在我们再也不用担心Button组件进行多余的渲染了。
// -> -> -> 如果您觉得这段代码没问题,那您可能需要重新学习一下hooks了
上述代码确实没有渲染的问题了,但是出现了一个更加严重的问题:代码逻辑错误
我们浅浅的测试一下。
//测试代码,可跳过
//默认on为true,调用4次toggle,期望结果为:[true, false, true, false, true]
function useToggle(on = true){
const [_on, setOn] = React.useState(on);
const _toggle = React.useCallback(() => {
setOn(!_on);
}, [])
return [_on, _toggle];
}
const values = [];
const App = ()