在 React 中如何防止代码爆炸
Functional Component 是很棒的东西
在写了很长一段时间的 useState
, useEffect
之后,发现 Functional Component 确实比 Class Component 更加方便,模糊了生命周期的概念,也没有很多令人上头 UNSAFE 方法。但是真正让我想要防止代码爆炸的其实是一条 lint 规则,就是一个方法不能超过 200 行。算上本身的逻辑代码,格式化之后的空行。其实很容易就写超过 200 行了,一个组件如果只有 200 行显然不怎么现实。如果说是要拆分子组件,在最外层组件也是会有很多 state 需要去维护,所以有一个地方肯定得爆炸。
Scenario 1
假设你有一个很简单的需求,就是写一个 Switch 用来控制一些简单的文字。
那么你的代码最初可能会长成这样:
import React, {useState} from 'react';
const App = () => {
const [state, setState] = useState('on');
return <div>
<div>State: {state}</div>
<div>
<button type="button" onClick={() => {
setState('on')
}}>
Turn On
</button>
<button type="button" onClick={() => {
setState('off')
}}>
Turn Off
</button>
<button type="button" onClick={() => {
state === '' ? setState('off') : setState('on')
}}>
Toggle
</button>
</div>
</div>
}
Scenario 2
实际上也不是不能被接受,因为这里逻辑其实并不复杂,稍微看一下也是非常简单明了的。那么接下来我们再改一个版本:
import React, {useState, useCallback} from 'react';
const App = () => {
const [state, setState] = useState('on');
const on = React.useCallback(() => {
setState('on');
}, []);
const off = React.useCallback(() => {
setState('off');
}, []);
const toggle = React.useCallback(() => {
setState(s => (s === 'on' ? 'off' : 'on'));
}, []);
return <div>
<div>State: {state}</div>
<div>
<button type="button" onClick={on}>
Turn On
</button>
<button type="button" onClick={off}>
Turn Off
</button>
<button type="button" onClick={toggle}>
Toggle
</button>
</div>
</div>
}
现在再来看一下,在 View 中代码显然变少了,也更好让人理解了。逻辑与视图分离了。
much better, so far so good.
Scenario 3
接着,当一个新的需求提了出来之后,这里你需要一个输入框。
const App = () => {
const [state, setState] = useState('on');
const [inputState, setInputState] = React.useState('');
const on = React.useCallback(() => {
setState('on')
}, [])
const off = React.useCallback(() => {
setState('off')
}, [])
const toggle = React.useCallback(() => {
setState(s => (s === 'on' ? 'off' : 'on'))
}, []);
const handleInputChange = React.useCallback(e => {
setInputState(e.target.value)
}, []);
const resetInput = React.useCallback(() => {
setInputState('')
}, []);
return <div>
<div>State: {state}</div>
<div>
<button type="button" onClick={on}>
Turn On
</button>
<button type="button" onClick={off}>
Turn Off
</button>
<button type="button" onClick={toggle}>
Toggle
</button>
</div>
<div>
<label htmlFor="randomWord">Random Word</label>
<input
type="text"
id="randomWord"
onChange={handleInputChange}
value={inputState}
/>
<button type="button" onClick={resetInput}>
Reset Input
</button>
</div>
</div>
}
从上面来看,我新加入的代码并不多,无非是多了一个 useState,已经两个方法。但是这仅仅是一个 input 框而已,所以如果你在多一些这样的需求,这样的组件,你的代码就炸啦。因为这样带来了一些问题:
- 你的方法以后离 useState 会很远,你需要来回滚动你的代码才能让你脑子记住
- 这样子的代码带来了我之前提到的问题,很容易就爆炸了,超过行数的限制
- 以后你的心智负担会很重,如果移除一些组件的时候,会遗漏一些方法或者 state
解决方案 useCustomHook is the rescue
import React, {useState, useMemo} from 'react';
const useOnOff = () => {
const [state, setState] = React.useState('off')
const handlers = useMemo(() => ({
on: () => {
setState('on')
},
off: () => {
setState('off')
},
toggle: () => {
setState(s => (s === 'on' ? 'off' : 'on'))
},
}), []);
return [state, handlers]
}
const useInput = () => {
const [state, setState] = React.useState('')
const handlers = React.useMemo(() => ({
handleInputChange: e => {
setState(e.target.value)
},
resetInput: () => {
setState('')
},
}),[])
return [state, handlers]
}
const App = () => {
const [state, { on, off, toggle }] = useOnOff()
const [inputState, { handleInputChange, resetInput }] = useInput()
return <div>
<div>State: {state}</div>
<div>
<button type="button" onClick={on}>
Turn On
</button>
<button type="button" onClick={off}>
Turn Off
</button>
<button type="button" onClick={toggle}>
Toggle
</button>
</div>
<div>
<label htmlFor="randomWord">Random Word</label>
<input
type="text"
id="randomWord"
onChange={handleInputChange}
value={inputState}
/>
<button type="button" onClick={resetInput}>
Reset Input
</button>
</div>
</div>
}
这样看起来是不是心智负担就少了很多很多!而且最重要的是,这两个 customHook 可以放到其他地方,以备不时之需,实际上 on off switch 这种在项目中是非常常见的,这样一来你就防止了代码爆炸了。
这其实是一个软件工程的非常常见的现象,如果你的心智出现了负担,那么多一层封装可以解决你的问题,如果还有,那就再来一层。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!