項目中遇到個問題,有一個數組參數,刪除數組中一個元素,並且重新改變state但是頁面沒有重新渲染,先面用一個簡單的todolist重現下問題
如下渲染出來menu,當我點擊刪除時觸發onClose事件,在onClose中直接對listData進行操作,打印出的數據是刪除后的,但是頁面沒有重新渲染
const data=[ {name:'小A',age:'10',id:'1'}, {name:'小B',age:'11',id:'2'}, {name:'小C',age:'10',id:'3'}, {name:'小D',age:'11',id:'4'} ] function ToDoList(){ const [listData,setListData] = useState([data]); const onClose=(newdata,e)=>{ e.stopPropagation(); e.preventDefault(); const currentIndex = listData.findIndex(item=>item.id===newdata.id); listData.splice(currentIndex,1) setListData(listData) } return ( <Menu selectedKeys={[currentId]}> { listData.map((item,index)=>{ return ( <Menu.Item key={index}> {item.name} <Icon type="close" onClick={(e) => onClose(item,e)} /> </Menu.Item> ) }) } </Menu> ) } export default ToDoList;
問題出在我不應該直接操作listData,因為直接操作listData使它的值直接變化,在通過setListData()修改他的狀態,這時候通過setListData()保存的最新狀態和listData是相同的,會默認為state並沒有發生改變,所有不會重新渲染,所以,我們需要在處理數據之前對listData做一次深拷貝,如下
const onClose=(newdata,e)=>{ e.stopPropagation(); e.preventDefault(); const currentIndex = listData.findIndex(item=>item.id===newdata.id); const newArray = _.map(taskbarData,(val) => { return val }) newArray.splice(currentIndex,1) setListData(newArray) }
這樣的話就可以完美解決了
總結:這里涉及到了深拷貝和淺拷貝的問題,
淺拷貝,就是兩個變量都是指向一個地址,改變了一個變量,那另一個變量也隨之改變。這就是淺拷貝帶來的副作用,兩個變量會相互影響到,因為它們指向同一個地址。如下當我改變newArray的值,listData也會隨之改變
const newArray = listData
深拷貝,就是互相獨立,指向的是不同的地址,一個變量改變了,另一個變量不會被影響到。
const newArray = _.map(taskbarData,(val) => { return val })