Javascript setState未正确更新状态

Javascript setState未正确更新状态,javascript,reactjs,Javascript,Reactjs,对不起,我真的错过了React中子组件的props中的state传输 我已经实现了一个包含3个组件的todo列表版本 有一个Form组件和一个ListTodo组件。该状态仅存储在App组件中 import React, {Component} from 'react'; import './App.css'; class App extends Component { constructor(props) { super(props); this.st

对不起,我真的错过了React中子组件的
props
中的
state
传输

我已经实现了一个包含3个组件的todo列表版本

有一个
Form
组件和一个
ListTodo
组件。该状态仅存储在
App
组件中

import React, {Component} from 'react';
import './App.css';

class App extends Component {

    constructor(props) {
        super(props);
        this.state = {
            tasks: ["un truc", "autre truc"]
        };
        this.addTask = this.addTask.bind(this);
    }

    addTask(task) {
        this.setState({
            tasks: this.state.tasks.push(task)
        })
    }

    render() {
        return (
            <div className="App">
                <Form onTaskAdded={ this.addTask }></Form>
                <ListTodo tasks={ this.state.tasks }></ListTodo>
            </div>
        );
    }
}

class Form extends Component {

    constructor(props) {
        super(props);
        this.state = {
            task: ""
        }

        this.handleChange = this.handleChange.bind(this);
        this.addTask = this.addTask.bind(this);
    }

    handleChange(event) {
        this.setState({
            task: event.target.value
        });
    }

    addTask(event) {
        this.props.onTaskAdded(this.state.task);
        event.preventDefault();
    }

    render() {
        return (
            <form onSubmit={ this.addTask }>
                <input placeholder="À faire" onChange={ this.handleChange }></input>
                <input type="submit"></input>
            </form>
        )
    }
}

class ListTodo extends Component {

    render() {
        const tasks = this.props.tasks.map((t, i) => (
                <li key={i}>{t}</li>
            ))

        return (
            <ul>{tasks}</ul>
        )
    }
}

export default App;
import React,{Component}来自'React';
导入“/App.css”;
类应用程序扩展组件{
建造师(道具){
超级(道具);
此.state={
任务:[“休战”、“休战”]
};
this.addTask=this.addTask.bind(this);
}
添加任务(任务){
这是我的国家({
任务:this.state.tasks.push(任务)
})
}
render(){
返回(
);
}
}
类形式扩展组件{
建造师(道具){
超级(道具);
此.state={
任务:“
}
this.handleChange=this.handleChange.bind(this);
this.addTask=this.addTask.bind(this);
}
手变(活动){
这是我的国家({
任务:event.target.value
});
}
添加任务(事件){
this.props.onTaskAdded(this.state.task);
event.preventDefault();
}
render(){
返回(
)
}
}
类ListTodo扩展组件{
render(){
const tasks=this.props.tasks.map((t,i)=>(
  • {t}
  • )) 返回(
      {tasks}
    ) } } 导出默认应用程序;
    开始时显示良好,因此
    列表TODO
    可以查看道具
    任务
    。但是在提交表单之后,我在
    ListTodo.render上得到一个错误:

    TypeError:this.props.tasks.map不是函数

    当我在console.log中记录
    this.props.tasks
    时,我不获取数组,而是获取数组的长度

    你知道为什么吗

    编辑: 谢谢你们的回答,伙计们,你们说得对。我错过了Array.push的行为

    但反应似乎仍然很奇怪。如果我让错误的代码
    this.setState({
    任务:this.state.tasks.push(任务)
    })

    然后一个
    console.log(JSON.stringify(this.state))
    显示:

    {“任务”:[“不停战”、“自动停战”、“不停战”]}

    无法信任控制台非常令人不安。根据以下内容记录…

    push()方法将一个或多个元素添加到数组的末尾,然后 返回数组的新长度

    从不返回结果数组,它返回数字,因此在添加第一个任务后,
    this.state.tasks
    将成为一个数字,并且在您尝试运行map on number时抛出错误

    你在这里犯了错误:

    addTask(task) {
        this.setState({
            tasks: this.state.tasks.push(task)
        })
    }
    
    这样写:

    addTask(task) {
        this.setState( prevState => ({
            tasks: [...prevState.tasks, task]
        }))
    }
    
    这里的另一个重要内容是,新状态将取决于以前的状态值,因此,不要在setState中使用
    this.state
    ,而是使用updater函数

    关于编辑部件的说明:

    两件重要的事情正在那里发生:

    1-setState是异步的,因此在setState之后,我们可以期望更新的状态值

    有关的更多详细信息,请查看此项

    2-Array.push总是通过将项推入原始数组来改变原始数组,因此您可以通过
    this.state.tasks.push()直接改变状态值


    有关设置状态的更多详细信息,请查看

    检查中的
    扩展运算符(…)

    检查此代码段:

    设a=[1,2,3,4];
    设b=a.推(5)//这将是一个数字
    log('a=',a);
    log('b=',b)问题在于如何在应用程序状态下添加任务

    addTask(task) {
        this.setState({
            tasks: this.state.tasks.push(task)
        })
    }
    
    请参见,添加元素后数组的。你真正想要的是

    此外,多亏了@t-j-crowder指针,正如@mayank shukla所报道的,你应该使用不同的方法来改变你的状态:

    addTask(task) {
        this.setState(function (state) {
            return {
                tasks: state.tasks.concat([ task ])
            }
        });
    }
    
    或者使用ES2015箭头、对象分解和阵列扩展:

    addTask(task) {
        this.setState(({ tasks }) => ({
            tasks: [ ...tasks, task ]
        }));
    }
    
    由于
    Component.prototype.setState
    可以是异步的,因此将函数传递给它将保证新状态值取决于右侧的当前先前值


    这意味着,如果两个或多个
    setState
    调用相继发生,您可以通过应用第二个来确保第一个调用的结果将被保留。

    正如其他答案所述,Array
    push
    方法不会返回数组。为了补充上面的答案,如果您正在使用ES6,那么使用spread操作符(您可以阅读更多有关它的信息)是一种很好且优雅的方法


    它本质上与使用
    concat
    方法相同,但我认为它具有更好的可读性。

    问题在于数组。push返回数组中的元素数,而不是更新的数组

    addTask(task) {
      this.setState({
        tasks: this.state.tasks.push(task)
      })
    }
    
    要解决此问题,您可以推送到state.tasks,然后稍后使用它设置state:

    addTask(task) {
      this.state.tasks.push(task);
      this.setState({
        tasks: this.state.tasks
      })
    }
    

    通过这种方式,您可以将state.task设置为更新后的数组。

    您可能会说为什么,甚至可能会参考文档中有关此内容的内容。。。特别是你改变了两件事(都很重要),你是对的。我错过了Array.push的行为。但是,如果我让
    this.setState({tasks:this.state.tasks.push(task)})
    ,那么
    console.log(JSON.stringify(this.state))
    会显示:
    {“tasks”:[“untruc”,“autre truc”,“aze”}
    17:12:52.634这里有两个重要的东西,1-setState是异步的,因此在setState之后,我们不能期望更新的状态值,2-您正在直接改变状态值数组。push将把元素推入主数组。有关setState异步行为的更多详细信息,请检查。感谢@MayankShukla!用你的ans
    addTask(task) {
      this.setState({
        tasks: this.state.tasks.push(task)
      })
    }
    
    addTask(task) {
      this.state.tasks.push(task);
      this.setState({
        tasks: this.state.tasks
      })
    }