React调用setState后未重新渲染?待办列表删除任务页面不更新
React待办列表删除后页面不更新的问题解决
问题根源
核心问题是状态层级不匹配:任务列表的数据源(tasks)存储在App组件的state中,但删除操作完成后,你在TaskItem组件里调用this.setState({tasks}),这只会更新TaskItem自己的state,并不会影响App组件的state。而页面渲染依赖的是App的state,所以只要App的state没变化,页面就不会自动刷新。
解决方案:通过回调函数传递状态更新逻辑
我们需要把更新App组件state的逻辑,通过props从父组件传递到子组件,让TaskItem在删除成功后触发这个逻辑,从而更新页面。
步骤1:在App组件中封装任务列表更新方法
修改App.js,把获取任务的逻辑封装成独立方法,并传递给TaskList:
import React from 'react'; import taskApi from "../api/task-api"; import TaskList from "./TaskList"; import {Button, Container} from "react-bootstrap"; class App extends React.Component { state = { tasks: [], } componentDidMount() { this.fetchTasks(); } // 封装获取任务列表的方法 fetchTasks = () => { taskApi.get('/tasks').then( res => { const tasks = res.data.data; this.setState({tasks}) } ); } render() { return( <Container> <h1>Task Manager</h1> <Button variant="primary" size="lg" className="add-task-button">Add Task</Button> {/* 将fetchTasks方法通过props传递给TaskList */} <TaskList tasks={this.state.tasks} fetchTasks={this.fetchTasks} /> </Container> ); } } export default App;
步骤2:在TaskList中传递方法给TaskItem
修改TaskList.js,把fetchTasks方法继续传递给每个TaskItem:
import React from 'react'; import Table from 'react-bootstrap/Table' import TaskItem from "./TaskItem"; class TaskList extends React.Component { render() { return( <Table striped bordered hover> <thead> <tr key="header"> <th>ID #</th> <th>Task Name</th> <th></th> </tr> </thead> <tbody> {this.props.tasks.map((task) => { // 将fetchTasks传递给TaskItem return <TaskItem task={task} key={task.id} fetchTasks={this.props.fetchTasks} /> })} </tbody> </Table> ); } } export default TaskList;
步骤3:在TaskItem中调用父组件的更新方法
修改TaskItem.js的deleteTask方法,删除成功后调用props中的fetchTasks来更新App的state:
import React from 'react'; import {Button, Modal} from "react-bootstrap"; import taskApi from "../api/task-api"; class TaskItem extends React.Component { constructor() { super(); this.state = { show: false, }; } showModal() { this.setState({show: true}); } closeModal() { this.setState({show: false}); } deleteTask(task_id) { this.setState({show: false}); taskApi.delete('/task/' + task_id).then(()=>{ // 调用父组件传递的方法,更新App的任务列表 this.props.fetchTasks(); }); } render() { return( <tr> <td>{this.props.task.id}</td> <td>{this.props.task.task_name}</td> <td> <Button variant="success" className="task-action-button">Complete</Button> <Button variant="secondary" className="task-action-button">Edit</Button> <Button variant="danger" className="task-action-button" onClick={()=>{this.showModal()}}>Delete</Button> <Modal show={this.state.show}> <Modal.Header>Confirm</Modal.Header> <Modal.Body> Are you sure you want to delete this task? <br/><br/> <strong>Task:</strong> <br/> {this.props.task.task_name} </Modal.Body> <Modal.Footer> <Button variant="secondary" onClick={()=>{this.closeModal()}}>Cancel</Button> <Button variant="danger" onClick={()=>{this.deleteTask(this.props.task.id)}}>Delete</Button> </Modal.Footer> </Modal> </td> </tr> ); } } export default TaskItem;
额外优化:减少API请求
上面的方案需要删除后重新请求整个任务列表,其实可以直接在App组件中过滤掉已删除的任务,省去一次API请求:
- 在
App.js中添加删除任务的方法:
deleteTask = (task_id) => { taskApi.delete('/task/' + task_id).then(()=>{ // 直接过滤state中的任务,无需重新请求API this.setState(prevState => ({ tasks: prevState.tasks.filter(task => task.id !== task_id) })); }); }
- 把
deleteTask传递给TaskList,再传递给TaskItem,然后在TaskItem的deleteTask方法中调用this.props.deleteTask(task_id)即可。
这样既减少了网络请求,也能实现页面实时更新。
内容的提问来源于stack exchange,提问作者Justin Simon
相关产品推荐
相关产品推荐

