У меня сейчас странная проблема.
У меня есть список задач, которые приходят через остальные 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)
Когда я удаляю задачу сверху или снизу, она обновляется нормально, но когда я делаю это из середины, нижняя исчезает, а та, которая должна быть удалена, остается / показывает. Когда вы обновляете его, то, конечно, все в порядке, но вопрос в том, почему это происходит? У меня есть сага о редуксе, которая снова выбирает задачи после удаления, и я могу подтвердить, что реквизиты тоже получают правильные данные.
ОБНОВЛЕНИЕ 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
Новый компонент TaskCard:
/* 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.