抱歉,我真的很想念React中state
个子组件中props
的传输。
我已经实现了一个包含3个组件的待办事项列表版本。
有一个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;
显示效果很好,ListTodo
可以看到道具tasks
。但在提交表单后,我在ListTodo.render
上收到错误:
TypeError:this.props.tasks.map不是函数
当我在console.log this.props.tasks
时,我没有得到我的数组,而是数组的长度。
你知道为什么吗?
修改: 谢谢你的回答,你说得对。我错过了Array.push的行为。
但React似乎仍然很奇怪。如果我让错误的代码
this.setState({
tasks: this.state.tasks.push(task)
})
然后显示console.log(JSON.stringify(this.state))
:
{"tasks":["un truc","autre truc","aze"]}
。
非常不安,无法信任console.log ......
答案 0 :(得分:6)
根据MDN DOC:
push()方法将一个或多个元素添加到数组的末尾 返回数组的新长度。
Array.push永远不会返回结果数组,它返回数字,因此在添加第一个任务后,this.state.tasks
变为一个数字,并且当您尝试在数字上运行地图时它会抛出错误。
你在这里犯了错误:
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之后我们可以期待更新的状态值。
查看此内容,详细了解 async behaviour of setState 。
2 - Array.push总是通过将项目推入该数组来改变原始数组,因此您可以通过this.state.tasks.push()
直接改变状态值。
检查 DOC ,了解有关setState的详细信息。
检查 MDN Doc 以查找spread operator (...)
。
检查此代码段:
let a = [1,2,3,4];
let b = a.push(5); //it will be a number
console.log('a = ', a);
console.log('b = ', b);
答案 1 :(得分:2)
问题出在你如何在应用程序状态中添加任务。
addTask(task) {
this.setState({
tasks: this.state.tasks.push(task)
})
}
添加元素后,请参阅数组的Array.prototype.push
returns the length。你真正想要的是probably Array.prototype.concat
。
addTask(task) {
this.setState({
tasks: this.state.tasks.concat([ 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
次呼叫一个接一个地发生,您可以确保通过应用第二个来保留第一个呼叫的结果。
答案 2 :(得分:1)
正如其他答案所述,Array push
方法不返回数组。只是为了补充上面的答案,如果您使用的是ES6,那么使用扩展运算符(您可以阅读更多关于它的here)这是一种优雅而优雅的方式。
this.setState({
tasks: [...this.state.tasks, task]
})
它与使用concat
方法基本相同,但我认为它具有更好的可读性。
答案 3 :(得分:0)
问题出在Array.push中,返回数组中元素的数量,而不是更新后的数组
addTask(task) {
this.setState({
tasks: this.state.tasks.push(task)
})
}
要解决此问题,您可以推送至state.tasks,然后在其后设置setState:
addTask(task) {
this.state.tasks.push(task);
this.setState({
tasks: this.state.tasks
})
}
通过这种方式将state.task设置为更新后的数组。