热门组件库都在使用的usePropsValue怎么写
点击关注公众号,“技术干货”及时达!
1、受控和非受控?大家可能经常会封装一些组件,纯UI组件也好,业务组件也好,但是不能脱离受控非受控的概念去写组件,这样很容易写出渲染次数过多的组件
?1.1、受控受控意味着「受代码控制」,例如一个Input的修改是你使用onChange将他的value修改为e.target.value1.2、非受控非受控意味着「代码无法改变组件的值」,组件往往只需要一个defaultValue,比如Input你可以不需要监听onChange,而是直接用form得到每个表单的输入,最后提交,所有组件的值是用户手动改变的,在react中往往体现为使用ref去拿到组件的引用。1.3、理解这个对写组件有什么帮助?你是否一股脑的接受用户的传入参数并手动set修改一次?实际对于某些组件,往往我们不需要手动修改组件的值,手动的set往往导致多次渲染例如表单,如果你只是需要表单的值,你没必要每个字段给一个value然后修改的时候set它同理还有一些组件例如开关,日历,在我们不需要控制组件的值情况下,我们直接使用非受控模式即可,减少代码编写量的同时,还减少了渲染次数1.4、什么是usePropsValue?先来看看antd-mobile的使用场景实际上我们写组件的时候,我们不希望去定死一个组件是受控还是非受控,因为就算当下他是非受控,在有一天迭代需求的时候,也可能变成受控模式但是我们不可能未卜先知的去预计到这一天,过于提早的思考太多,反而影响代码的实现,usePropsValue就是为了这种场景而诞生的,将setState这一步放到了usePropsValue当中所以受控和非受控的参数我们都收集起来:「value,defaultValue,onChange」,让usePropsValue去判断实际传入的是什么,如果只传递了defaultValue那么显然是「非受控模式」,如果同时传递了value和onChange那么显然是「受控模式」简单看看usePropsValue的实现
2、usePropsValue编写思路我们希望使用usePropsValue以后就和正常使用useState一样,但是这个setState的操作逻辑在usePropsValue中,我们在代码中只需要const[selfValue,setSelfValue]=usePropsValue({
value:props.value,
defaultValue:props.defaultValue,
onChange:props.onChange
})
入参只有defaultValue的时候,使用useRef修改current入参数有value和onChange的时候要将onChange作为setState返回并修改value,这里要注意onChange3、编写一个简单的usePropsValue因为为了所有组件通用,入参用泛型useRef判断是defaultValue还是value这里要注意因为非受控用的是useRef不会触发组件的更新渲染,所以这里我们使用ahooks更新同理也可以自己写一个state去更新渲染状态import{useUpdate}from'ahooks'
import{SetStateAction,useRef}from'react'
typeOptions={
value?:T
defaultValue:T
onChange?:(v:T)=void
}
exportconstusePropsValue=T(options:Options)={
const{value,defaultValue,onChange}=options
conststateRef=useRef(value!==undefined?value:defaultValue)
if(value!==undefined){
stateRef.current=value
}
constupdate=useUpdate()
//setState用户传入的可能是函数,需要判断当是函数的时候直接更新为函数return的值
constsetState=(v:SetStateAction)={
constnextValue=
typeofv==='function'?(vas(preState:T)=T)(stateRef.current):v
stateRef.current=nextValue
update()
returnonChange?.(nextValue)
}
return[stateRef.current,setState]asconst
}
4、优化方案因为同步写法会直接更新stateRef,所以当value变化的时候要对比一下,if (nextValue === stateRef.current) return使用useCallBack或者useMemoizedFn包裹setState「避免不必要的重新渲染」:如果 setState 函数在每次渲染时都被重新创建,那么它的引用就会发生变化,可能会导致依赖它的子组件或 useEffect 钩子重新执行,这可能会引发不必要的重新渲染或副作用。而使用 useMemoizedFn 可以确保函数的引用是稳定的,除非其依赖项发生变化。「性能优化」:在某些场景下,函数可能会被频繁调用。如果每次都重新创建函数对象可能会增加内存和性能开销。使用 useMemoizedFn 可以减少这类开销。「稳定的回调函数」:在某些情况下,组件可能会传递 setState 给子组件或其他钩子。如果这些子组件或钩子依赖于稳定的回调函数,那么使用 useMemoizedFn 就可以确保它们收到的始终是同一个函数实例,避免因为函数引用变化而导致的不必要更新。5、结合组件实现在代码仓库实现了一个Switch组件并使用usePropsValue有兴趣可以看看https://github.com/Youngzx88/article-demo/tree/main/use-props-value6、总结其实多看看这种开源的组件库,会发现有很多类似的hooks封装,这都是大家互相借鉴+创新,通过优秀的设计模式实现的多了解了解这种hooks有助于写出高可维护的组件,像usePropsValue就可以让我们无脑去使用,不需要管组件本身是受控还是非受控,全看你的入参是什么点击关注公众号,“技术干货”及时达!
阅读原文
网站开发网络凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设、网站改版、域名注册、主机空间、手机网站建设、网站备案等方面的需求...
请立即点击咨询我们或拨打咨询热线:13245491521 13245491521 ,我们会详细为你一一解答你心中的疑难。 项目经理在线