Реагирующий дочерний компонент не рендерит на нем изменение состояния

У меня есть компонент 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
Другие вопросы по тегам