React删除数组及localStorage列表项后视图未实时更新问题
问题根源
- 子组件中通过
const [deleted, setDelted] = useState(store)将父组件传入的列表数据拷贝为本地状态,这个初始化操作仅在子组件首次挂载时执行一次,后续父组件传入的store更新时,本地的deleted不会自动同步。 - 点击Yes按钮时,所有修改操作都只作用在子组件本地的
deleted状态上,没有将删除后的结果同步回父组件。父组件用来渲染实际列表的源store没有发生变化,自然不会触发视图重渲染,只有其他操作触发父组件重渲染时,才会感知到数据变动。 - 子组件额外维护了
no状态控制遮罩显隐,和父组件通过props.setDel控制的遮罩状态重复,很容易出现状态不同步的问题。
修复方法
遵循React单向数据流原则:哪个组件维护数据,就由哪个组件负责修改数据,子组件不存冗余的同源状态,仅通过父组件传入的回调触发数据修改。
- 先在父组件中实现删除逻辑,将删除方法通过props传给子组件:
// 父组件代码示例 import { useState, useCallback } from 'react'; import Delete from './Delete'; function Parent() { const [store, setStore] = useState(() => { // 初始化时从localStorage读取数据 return Object.keys(localStorage) .filter(key => key.startsWith('task_')) // 按自身存储key规则过滤即可 .map(id => JSON.parse(localStorage.getItem(id))); }); const [delVisible, setDelVisible] = useState(false); const [currentDelId, setCurrentDelId] = useState(null); // 定义删除逻辑,维护源store const handleDelete = useCallback((id) => { const updatedStore = store.filter(task => task.id !== id); setStore(updatedStore); localStorage.removeItem(id); }, [store]); return ( <div> {/* 列表渲染逻辑 */} {store.map(task => ( <div key={task.id}> <span>{task.content}</span> <button onClick={() => { setCurrentDelId(task.id); setDelVisible(true); }}>删除</button> </div> ))} {/* 给删除组件传入所需props */} {delVisible && ( <Delete id={currentDelId} setDel={setDelVisible} onDelete={handleDelete} /> )} </div> ) } export default Parent;
- 简化子组件代码,删除冗余的本地状态,直接调用父组件传入的方法完成操作:
import React from "react"; import styles from "./Delete.module.css"; function Delete(props) { const noBtnHandler = () => { props.setDel(false); }; const yesBtnHandler = () => { props.onDelete(props.id); props.setDel(false); }; return ( <div className={styles.delOn}> <section> <div> <h3>Are you Sure ?</h3> </div> <div> <button type="button" onClick={yesBtnHandler}> Yes </button> <button type="button" onClick={noBtnHandler}> No </button> </div> </section> </div> ); } export default Delete;
注意事项
- 不要在子组件中拷贝父组件传入的、用于页面渲染的源数据到本地state,否则极易出现数据不同步的问题。
- 同一份状态只需要在最上层用到它的组件中维护一次,下层组件通过props获取状态、通过回调触发修改即可,不要重复维护多份状态。
- 修改状态后视图不更新时,优先检查是不是修改了非state的副本,或者修改的状态和渲染用的状态不是同一份。
内容的提问来源于stack exchange,提问作者Abhishek Lingwal
相关产品推荐
相关产品推荐

