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緩存的是整個函數
問題解決