我现在面临一个奇怪的问题。我有一个通过 rest api 来的任务列表。我创建了一个自定义卡片组件来显示它。
/* eslint-disable import/first */
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Grid from 'material-ui/Grid';
import Paper from 'material-ui/Paper';
import List, { ListItem, ListItemIcon, ListItemText } from 'material-ui/List';
import Button from 'material-ui/Button';
import Card, { CardActions, CardContent } from 'material-ui/Card';
import Typography from 'material-ui/Typography';
import TextField from 'material-ui/TextField';
import { LinearProgress } from 'material-ui/Progress';
import Modal from 'react-responsive-modal';
var Moment = require('moment');
import TaskActions from '../redux/TaskRedux'
import ProgressColumn from './Progress'
import TaskCard from './Card'
import AddTaskCard from './AddTaskCard'
import { connect } from 'react-redux'
import '../styles/main.css';
export class Container extends Component{
constructor(props){
super(props);
this.state = {
fetching: this.props.fetching,
taskName: null,
showError: false,
openEditModal: false,
editTaskName: null,
showUpdateError: false,
toBeUpdatedTask: null,
progressTasks:[],
tasks: []
}
}
componentDidMount(){
this.props.getTasks()
}
componentDidUpdate(prevProps, prevState) {
if(prevProps !== this.props){
this.setState({fetching: this.props.fetching,
tasks: this.props.tasks})
}
}
render(){
let {fetching, progressTasks} = this.state
let {tasks} = this.props
if(tasks)
tasks.map(i => console.log(i.title))
return (
<div className="grid-root">
<Grid container spacing={24}>
<Grid item xs={3} sm={3}>
<Paper className="task-list-view">
<List className="task-list">
{tasks && tasks.map((item,i) => (
<ListItem key={`item-${i}`}>
<TaskCard task={item} key={`item-${i}`}/>
</ListItem>
))}
</List>
<AddTaskCard/>
</Paper>
{fetching ? (<LinearProgress color="secondary" />): ('')}
</Grid>
<Grid item xs={3} sm={3}>
<Paper className="task-list-view">
<ProgressColumn progressTasks={progressTasks}/>
</Paper>
</Grid>
</Grid>
</div>
)
}
}
const mapStateToProps = (state) => {
return {
fetching: state.task.fetching,
tasks: state.task.tasks,
}
}
const mapDispatchToProps = (dispatch) => {
return {
getTasks: () => dispatch(TaskActions.fetchTasks()),
deleteTask: (taskId) => dispatch(TaskActions.deleteTask(taskId)),
updateTask: (taskId,title) => dispatch(TaskActions.updateTask(taskId,title)),
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Container)
这是卡片组件:
/* eslint-disable import/first */
import React, { Component } from 'react';
import { connect } from 'react-redux'
import Card, { CardActions, CardContent } from 'material-ui/Card';
import Button from 'material-ui/Button';
import Typography from 'material-ui/Typography';
import TaskActions from '../redux/TaskRedux'
import EditModal from './EditModal'
var Moment = require('moment');
export class TaskCard extends Component{
constructor(props){
super(props)
this.state = {
openEditModal: false,
editTaskName: null,
task: this.props.task
}
}
// handle edit of task name
handleTaskEdit(task){
console.log("edit task", task)
// this.setState({openEditModal: true, editTaskName: task.title, toBeUpdatedTask: task})
this.props.editTask(task)
}
// handle start task button click
// Will push the tasks for progressTasks state
handleStartTask(task){
// this.setState({
// progressTasks: [...this.state.progressTasks, task]
// })
}
// handle deletion of the task
handleTaskDelete(taskId){
console.log(taskId)
this.props.deleteTask(taskId)
// this.props.getTasks()
}
render(){
let {task} = this.state
let created = Moment(task.created).format("Do MMM YYYY")
console.log("task", task)
return (
<Card className="task-card" key={task.id}>
<EditModal/>
<CardContent>
<Typography variant="headline" component="h2">
{task.title}
</Typography>
<Typography color="textSecondary">
{created}
</Typography>
</CardContent>
<CardActions>
<Button size="small" color="primary" onClick={this.handleTaskEdit.bind(this, task)}>Edit</Button>
<Button size="small" color="primary" onClick={this.handleStartTask.bind(this, task)}>Start Task</Button>
<Button size="small" color="secondary" onClick={this.handleTaskDelete.bind(this, task.id)}>Delete</Button>
</CardActions>
</Card>
)
}
}
const mapStateToProps = (state) => {
return {
}
}
const mapDispatchToProps = (dispatch) => {
return {
getTasks: () => dispatch(TaskActions.fetchTasks()),
deleteTask: (taskId) => dispatch(TaskActions.deleteTask(taskId)),
editTask: (currentTask) => dispatch(TaskActions.editTask(currentTask))
}
}
export default connect(mapStateToProps, mapDispatchToProps)(TaskCard)
当我从顶部或底部删除任务时,它会更新得很好,但是当我从中间删除时,底部的任务会消失,而要删除的任务仍然会保留/显示。当你刷新它时,当然一切都很好,但问题是,为什么会发生这种情况?我有一个 redux saga,它在删除操作后再次获取任务,我可以确认 props 也确实获得了正确的数据。
更新 1
所以,我试图从我的最后调试它。看起来 TaskCard 有点缓存道具。
在{item.title}
添加的图像中,正下方是渲染任务卡的位置,两者都有不同的标题,但{item.title}
都是正确的。
更新 2
根据 jmathew,回答,我将 ListItem 和 TaskCard 的键更新为 item.id,因此删除有效,但更新仍然无效。同样,根据更新 1,它仍然显示错误的标题,但 {item.title} 是正确的。所以,这部分代码现在看起来像:
<List className="task-list">
{tasks && tasks.map((item,i) => (
<ListItem key={item.id}>
{item.title}
<TaskCard item={item} key=
{`item-${item.id}`}/>
</ListItem>
))}
</List>
更新 3
新的任务卡组件:
/* eslint-disable import/first */
import React, { Component } from 'react';
import { connect } from 'react-redux'
import Card, { CardActions, CardContent } from 'material-ui/Card';
import Button from 'material-ui/Button';
import Typography from 'material-ui/Typography';
import TaskActions from '../redux/TaskRedux'
import EditModal from './EditModal'
var Moment = require('moment');
export class TaskCard extends Component{
constructor(props){
super(props)
this.state = {
openEditModal: false,
editTaskName: null,
item: this.props.item
}
}
// handle edit of task name
handleTaskEdit(task){
console.log("edit task", task)
// this.setState({openEditModal: true, editTaskName: task.title, toBeUpdatedTask: task})
this.props.editTask(task)
}
// handle start task button click
// Will push the tasks for progressTasks state
handleStartTask(task){
// this.setState({
// progressTasks: [...this.state.progressTasks, task]
// })
}
// handle deletion of the task
handleTaskDelete(taskId){
// console.log(taskId)
this.props.deleteTask(taskId)
// this.props.getTasks()
}
componentDidUpdate(prevProps, prevState, snapshot){
console.log("update ", prevProps, prevState)
}
render(){
let {item} = this.state
let created = Moment(item.created).format("Do MMM YYYY")
console.log("item",item)
return (
<Card className="task-card" key={`task-${item.id}`}>
<EditModal/>
<CardContent>
<Typography variant="headline" component="h2">
{item.title}
</Typography>
<Typography color="textSecondary">
{created}
</Typography>
</CardContent>
<CardActions>
<Button size="small" color="primary" onClick={this.handleTaskEdit.bind(this, item)}>Edit</Button>
<Button size="small" color="primary" onClick={this.handleStartTask.bind(this, item)}>Start Task</Button>
<Button size="small" color="secondary" onClick={this.handleTaskDelete.bind(this, item.id)}>Delete</Button>
</CardActions>
</Card>
)
}
}
const mapStateToProps = (state) => {
return {
}
}
const mapDispatchToProps = (dispatch) => {
return {
getTasks: () => dispatch(TaskActions.fetchTasks()),
deleteTask: (taskId) => dispatch(TaskActions.deleteTask(taskId)),
editTask: (currentTask) => dispatch(TaskActions.editTask(currentTask))
}
}
export default connect(mapStateToProps, mapDispatchToProps)(TaskCard)
正如您在上图中看到的,卡片旁边的标题是更新的标题,由编辑按钮触发,但同样的内容不会传递给 TaskCard 组件。在屏幕截图中,有一个控制台输出,其中“update”行表明更改没有触发 componentDidUpdate。