使用usecallback/useMemo+usereducer解决单独使用usereducer出现的重复渲染问题
react中,单独使用usereducer的hooks进行开发的话会出现重复渲染的情况,代码如下:
// const setHotelList= const [hotelList,dispatchHotelList]=useReducer((state: any[],action: any)=>{ switch(action.type){ //会发现这样的地方不走usecallback会输出两次 case 'add': console.log([...state,action.payload]) return [...state,action.payload]
case 'modify':
return state.map(item=>{
return item.id===action.payload.id?{...item,checked:action.payload.checked}:item
})
default: return state } },[]) const addArr=()=>{ let id= Math.floor(Math.random()*100+1); var Arr = ["王","李","张","赵","陈","刘"]; var nameArr=['香蕉','苹果','柚子','橘子','菠萝']
//这里是随机获取数组元素的写法 var idx = Math.floor(Math.random() * Arr.length + 1)-1; var nameIdx = Math.floor(Math.random() * nameArr.length + 1)-1; dispatchHotelList({payload:{name:`${Arr[idx]}${nameArr[nameIdx]}`,id,checked:false},type:'add'}) } const selItem=(item:any)=>{ dispatchHotelList({payload:item,type:'modify'}) } return ( <> <ul> { hotelList.map((item: any,index)=>{ return <li key={index} style={{backgroundColor:`${item.checked?'green':'red'}`}} onClick={()=>{selItem(item)}}>{item.name}</li> }) } </ul> <button onClick={addArr}>添加</button> </> );
对于出现的问题,可以通过usecallback进行解决,这个钩子只有在依赖项变更后才会重新进行渲染,官网解释如下:
把内联回调函数及依赖项数组作为参数传入 useCallback
,它将返回该回调函数的 memoized 版本,该回调函数仅在某个依赖项改变时才会更新。当你把回调函数传递给经过优化的并使用引用相等性去避免非必要渲染(例如 shouldComponentUpdate
)的子组件时,它将非常有用。
所以改造后可以这么写:
const setHotelList= useCallback((state: any[],action: any)=>{ switch(action.type){ //会发现这样的地方不走usecallback会输出两次 case 'add': console.log([...state,action.payload]) return [...state,action.payload]
case 'modify':
return state.map(item=>{
return item.id===action.payload.id?{...item,checked:action.payload.checked}:item
})
default: return state } },[]) // const setHotelList= const [hotelList,dispatchHotelList]=useReducer(setHotelList,[]) const addArr=()=>{ let id= Math.floor(Math.random()*100+1); var Arr = ["王","李","张","赵","陈","刘"]; var nameArr=['香蕉','苹果','柚子','橘子','菠萝'] var idx = Math.floor(Math.random() * Arr.length + 1)-1; var nameIdx = Math.floor(Math.random() * nameArr.length + 1)-1; dispatchHotelList({payload:{name:`${Arr[idx]}${nameArr[nameIdx]}`,id,checked:false},type:'add'}) } const selItem=(item:any)=>{ dispatchHotelList({payload:item,type:'modify'}) }
使用useMemo可以如下写法:
const setHotelList= useMemo(()=>{ return (state: any[],action: any)=>{ switch(action.type){ //会发现这样的地方不走usecallback会输出两次 case 'add': console.log([...state,action.payload]) return [...state,action.payload] case 'modify': return state.map(item=>{ return item.id===action.payload.id?{...item,checked:action.payload.checked}:item }) default: return state } } },[])
这里useMemo和useCallBack区别在于。useMemo缓存的是函数的结果,而useCallBack缓存的是整个函数
问题解决
积累小的知识,才能成就大的智慧,希望网上少一些复制多一些原创有用的答案