使用redux-thunk做CRUD时useSelector返回data作为useEffect依赖触发无限重渲染如何解决
问题根源
- 无限渲染:你把
data加入useEffect依赖后,dispatch(getItems())会更新store中的data,data变动又会触发useEffect重新执行getItems,形成死循环。 - 删除后列表不更新:删除接口调用成功后,你仅更新了store中的
deleted状态,既没有修改列表数据data,也没有触发最新列表的拉取逻辑,data本身没有变化,所以监听data?.length也不会生效。
最优解决方案(无需修改组件代码,无额外性能损耗)
不需要改动表格组件的useEffect,保持原依赖[dispatch]即可,只需要调整删除相关的逻辑,有两种可选实现:
方案1:删除成功后主动拉取最新列表
调整删除确认逻辑,等待删除接口调用完成后,主动触发getItems拉取最新列表,自动更新store中的data,组件会监听到data变化自动重渲染:
// 修改删除确认函数为异步逻辑 const sweetAlertConfirmDeleteItem = async (id, dispatch) => { Swal.fire({ title: 'Are you sure?', text: "You won't be able to revert this!", icon: 'warning', showCancelButton: true, confirmButtonColor: '#3085d6', cancelButtonColor: '#d33', confirmButtonText: 'Yes, delete it!' }) .then(async (result) => { if (result.isConfirmed) { // 等待删除接口执行完成 await axios.delete(`${baseURL}${id}`); dispatch({ type: types.delete, deletedItem: 'Item deleted' }) // 主动拉取最新列表,更新store中的data await dispatch(getItems()) Swal.fire( 'Deleted!', 'Your file has been deleted.', 'success' ) } }) }
方案2:本地直接更新列表数据(性能更好,少一次网络请求)
删除成功后不需要重新拉取列表,直接在reducer中过滤掉已删除的条目即可,首先调整删除时的dispatch逻辑:
// 调整sweetAlertConfirmDeleteItem中的dispatch代码 dispatch({ type: types.delete, deletedItem: 'Item deleted', deletedId: id // 传递要删除的条目id })
再修改reducer中types.delete的处理逻辑:
case types.delete: return { ...state, // 直接过滤掉已删除的条目,更新data data: state.data?.filter(item => item.id !== action.deletedId) || state.data, deleted: action.deletedItem }
两种方案任选其一即可,都不需要用到memo/useMemo/useCallback,也不会出现无限渲染问题。
内容的提问来源于stack exchange,提问作者Maykel
相关产品推荐
相关产品推荐

