Реагирующий дочерний компонент не рендерит на нем изменение состояния
У меня есть компонент Tasks, который возвращает другие компоненты. Однако, когда я изменяю состояние одного из дочерних компонентов из компонента "Задачи", он НЕ рендерится повторно.
Я передаю состояние "newTaskAdded" от родителя к дочернему элементу в качестве подпорки и назначаю его дочернему состоянию для повторного рендеринга дочернего компонента, но это все еще не происходит.
Моя цель: когда пользователь добавляет задачу, я хочу, чтобы она немедленно отображалась на экране, то есть пользователю необходимо обновить страницу, чтобы увидеть новую задачу.
Tasks.jsx:
import React , { Component } from 'react'
import axios from 'axios'
import Name from './Name.jsx'
import ShowTasks from './ShowTasks.jsx'
class Tasks extends Component {
constructor(props) {
super(props)
this.state={
task: '',
newTaskAdded:false,
newTask:[],
}
this.handleChange = this.handleChange.bind(this)
this.addTask = this.addTask.bind(this)
}
handleChange(event) {
this.setState({task: event.target.value})
}
addTask() {
axios.post('/api/addtask',{
name:this.props.name,
task:this.state.task
})
.then((res) => {
if(res.status=='200'){
this.setState ({task:''})
this.setState ({newTaskAdded:true})
this.setState ({newTask: res.data.message[res.data.message.length-1] })
}
})
.catch((err) => {
if(err) throw err
})
}
render() {
return (
<div>
<div>
<Name name={this.props.name} />
</div>
<div>
<input value={this.state.task} onChange={this.handleChange} type="text" name="task" />
<button type="button" onClick={this.addTask}>Add Task</button>
</div>
<ShowTasks name={this.props.name} updated={this.state.newTaskAdded} />
</div>
)
}
}
export default Tasks
ShowTasks.jsx
import React , { Component } from 'react'
import axios from 'axios'
import Completed from './Completed.jsx'
import NotCompleted from './NotCompleted.jsx'
class ShowTasks extends Component {
constructor(props) {
super(props)
this.state = {
tasks:[],
updated:this.props.updated
}
}
componentWillMount(){
axios.post('/api/loadtasks', {
name: this.props.name
})
.then((res) => {
console.log('res', res);
this.setState ({tasks:res.data.tasks})
})
.catch((err) => {
throw err
})
}
render() {
return (
<div className='pointer'>
{this.state.tasks.map((task) => {
if(task.completed) {
return <Completed key={task._id} {...task} />
}
else {
return <NotCompleted key={task._id} {...task} />
}
})}
</div>
)
}
}
export default ShowTasks
2 ответа
Так что проблема в функции вашего ребенка, где вы устанавливаете реквизиты в состояние,
Вы устанавливаете реквизиты в состояние конструктора, и конструктор вызывается не каждый раз, когда реквизиты меняются, а только в первый раз, когда компонент рендерится, и, следовательно, состояние не обновляется с правильными значениями.
Вы должны установить реквизиты в функции componentWillReceiveProps, которая вызывается при каждом рендеринге родительского компонента.
class ShowTasks extends Component {
constructor(props) {
super(props)
this.state = {
tasks:[],
updated:this.props.updated
}
}
componentWillReceiveProps(nextProps) {
this.setState({updated: nextProps.updated});
}
componentWillMount(){
axios.post('/api/loadtasks', {
name: this.props.name
})
.then((res) => {
console.log('res', res);
this.setState ({tasks:res.data.tasks})
})
.catch((err) => {
throw err
})
}
render() {
return (
<div className='pointer'>
{this.state.tasks.map((task) => {
if(task.completed) {
return <Completed key={task._id} {...task} />
}
else {
return <NotCompleted key={task._id} {...task} />
}
})}
</div>
)
}
}
export default ShowTasks
Узнайте больше о функциях жизненного цикла и когда их использовать здесь:
ХОРОШО! решил:
Tasks.jsx:
import React , { Component } from 'react'
import axios from 'axios'
import Name from './Name.jsx'
import ShowTasks from './ShowTasks.jsx'
class Tasks extends Component {
constructor(props) {
super(props)
this.state={
user:this.props.user,
task:'',
newTask:[],
}
this.handleChange = this.handleChange.bind(this)
this.addTask = this.addTask.bind(this)
}
handleChange(event) {
this.setState({task: event.target.value})
}
addTask() {
axios.post('/api/addtask',{
name:this.state.user.name,
task:this.state.task
})
.then((res) => {
if(res.status=='200'){
this.setState ({user:this.state.user})
this.setState ({newTask: res.data.message[res.data.message.length-1] })
}
})
.catch((err) => {
if(err) throw err
})
}
render() {
return (
<div>
<div>
<Name name={this.props.user.name} />
</div>
<div>
<input value={this.state.task} onChange={this.handleChange} type="text" name="task" />
<button type="button" onClick={this.addTask}>Add Task</button>
</div>
<ShowTasks user={this.state.user}/>
</div>
)
}
}
export default Tasks
ShowTasks.jsx:
import React , { Component } from 'react'
import axios from 'axios'
import Completed from './Completed.jsx'
import NotCompleted from './NotCompleted.jsx'
class ShowTasks extends Component {
constructor(props) {
super(props)
this.state = {
user: this.props.user,
tasks:[],
}
this.loadTasks=this.loadTasks.bind(this)
}
loadTasks() {
axios.post('/api/loadtasks', {
name: this.state.user.name
})
.then((res) => {
this.setState ({tasks:res.data.tasks})
})
.catch((err) => {
throw err
})
}
componentWillReceiveProps(nextProps) {
this.loadTasks()
}
render() {
return (
<div className='pointer'>
{this.state.tasks.map((task) => {
if(task.completed) {
return <Completed key={task._id} {...task} />
}
else {
return <NotCompleted key={task._id} {...task} />
}
})}
</div>
)
}
}
export default ShowTasks