React中为何使用useToggle自定义Hook而非直接用useState
为什么要封装useToggle,直接用useState不行吗?
useToggle根本不是什么有特殊能力的高级Hook,说白了就是把大家写吐了的布尔值切换逻辑抽了个公共方法而已,和你把项目里重复写了十遍的通用逻辑封成工具函数是一个道理,不存在“用useState就更好”或者“必须用useToggle”的绝对说法,只是抽出来之后好处确实不少:
- 省得一遍遍写重复代码
做过中大型项目的都知道,一个页面里能有八九个布尔开关:模态框显隐、下拉菜单开/关、折叠面板展开关、表单里的各种开关项、切换按钮状态……要是全用原生useState,每处都得先声明state,再写个const toggleXxx = () => setXxx(prev => !prev),写个十次二十次全是一模一样的代码,纯纯重复劳动。用封装好的useToggle一行就能拿到状态和切换方法,省下来的时间摸鱼不好吗。 - 少写无意义的bug
自己写切换逻辑太容易踩坑了:要么图省事写成setVisible(!visible),刚好这个切换方法放在异步请求回调、防抖函数这种闭包里,直接拿到旧的state值,点半天模态框关不上,找bug找半小时;要么写完toggle函数忘了包useCallback,传给子组件的时候每次重渲染都生成新函数,导致memo优化直接失效,平白无故多一堆重渲染。
这些坑useToggle里早就帮你避完了:内部固定用函数式更新拿最新状态取反,toggle方法用useCallback做了缓存,引用永远稳定,直接拿来用就行,不用每次写都记着要加这两个细节。 - 写代码更顺手,读代码更直白
用useToggle的时候事件绑定都能少写个匿名函数,直接<button onClick={toggle}>点我开关</button>就行,不用写onClick={() => setVisible(prev => !prev)}这一长串,扫一眼代码就知道这是个切换状态的操作,语义特别清楚。大部分实现里的useToggle还支持传参:调toggle(true)直接把状态设为开,toggle(false)直接关,一个方法顶三个用,比分开写setShow、setHide、toggle三个函数方便多了。
当然也不是说啥场景都硬要套useToggle。如果你写的组件里就一个布尔值,切换逻辑也就用一次,那直接用useState反而是更简单的选择,没必要为了封装而封装。抽自定义Hook的唯一标准就是:相同的逻辑你已经重复写了三遍以上,抽出来就绝对不亏。
useToggle自定义Hook实现
import { useCallback, useState } from 'react'; // 使用示例 function App() { // 调用Hook,返回当前状态值和切换函数 const [isTextChanged, setIsTextChanged] = useToggle(); return ( <button onClick={setIsTextChanged}>{isTextChanged ? 'Toggled' : 'Click to Toggle'}</button> ); } // Hook实现:入参是初始布尔值,默认是false const useToggle = (initialState = false) => { // 初始化状态 const [state, setState] = useState(initialState); // 缓存切换函数,避免往下传的时候导致子组件非必要重渲染 // 逻辑很简单:把状态设为之前值的相反值 const toggle = useCallback(() => setState(state => !state), []); return [state, toggle] }
直接用原生useState的写法参考
const [shouldDisplayModal, setShouldDisplayModal] = useState(false); <> {shouldDisplayModal && ( <Modal> <ModalContent modalText={messageContent} primaryButtonText={buttonText} secondaryButtonText={NO_MESSAGE} modalIconState={modalIconState} handleClick={toggleSaveModal} /> </Modal> )} <Button handleClick={toggleSaveModal} mainButton={false}> Save </Button> <Button handleClick={togglePublishModal} mainButton={true}> Publish </Button> </>
内容的提问来源于stack exchange,提问作者Un Jin Jang
相关产品推荐
相关产品推荐

