javascript - 父状态更新时反应父组件重置子组件状态
问题描述
我有一个名为的父组件ToDoLists
,其中包含一个输入并允许您输入一个新的待办事项列表名称。该组件映射到组件状态中的列表数组以创建不同的List
组件。
该List
组件允许您添加待办事项。例如:早餐、淋浴、剃须作为待办事项的早晨例行清单。
我可以让ToDoLists
组件创建新List
组件。但是,当我在组件状态中添加待办事项时List
,在父组件的输入中重新键入似乎会擦除子组件的状态。
我不确定这是否是尝试这样做的正确方法。这是因为我prevState
在添加新列表时需要通过吗?
ToDoLists 组件
import React, { Component } from 'react';
import '../App.css';
import List from './list.js';
class ToDoLists extends Component {
constructor(props){
super(props)
this.state = {
term: '',
list: []
};
}
onChange = (event) => {
this.setState({term: event.target.value});
}
onSubmit = (event) => {
event.preventDefault()
this.setState({
term: '',
list: [...this.state.items, this.state.term]
})
}
render() {
const generateKey = (x) => {
return `${x}_${new Date().getTime()}`
};
return(
<div>
<h3>ToDo Lists Component</h3>
<form onSubmit={this.onSubmit}>
<input placeholder='Add A New List' value={this.state.term} onChange={this.onChange}/>
<button className='btn btn-sm btn-dark'>Submit</button>
</form>
<br/><br/>
{
this.state.list.map((data) => {return(<List title={data} key={generateKey(data)}/>)})
}
</div>
)
}
}
export default ToDoLists
列表组件
import React, { Component } from 'react';
import '../App.css';
class List extends Component {
constructor(props){
super(props)
this.state = {
term: '',
items: []
};
this.onChange = this.onChange.bind(this);
}
onChange = (event) => {
this.setState({term: event.target.value});
}
onSubmit = (event) => {
event.preventDefault()
this.setState({
term: '',
items: [...this.state.items, this.state.term]
})
}
render() {
const generateKey = (x) => {
return `${x}_${new Date().getTime()}`
}
return(
<div>
<h3>{this.props.title}</h3>
<form onSubmit={this.onSubmit}>
<input placeholder='Add New Todo Item' value={this.state.term} onChange={this.onChange}/>
<button className='btn btn-sm btn-dark'>Submit</button>
</form>
<ul>
{
this.state.items.map((item) => {return(<li key={generateKey(item)}>{item}</li>)})
}
</ul>
</div>
)
}
}
export default List
解决方案
重置是由这个小部分引起的:
key={generateKey(data)}
每当您重新渲染父级时,子级都会获得新的密钥,因为generateKey
它会返回一个几乎随机的密钥。在进行差异化时,React 会尝试找出哪些组件被删除以及哪些组件被添加,并且它使用key
prop 来简化这一点。如果键是先前子元素和当前子元素的一部分,则元素将保持原样,如果键消失,则组件将被销毁,如果键是新的,它将创建一个新组件。因此,在您的情况下,所有s 都将被销毁,并且无论何时运行List
都会创建新的。ToDoLists.render()
要改变这一点,只需key
坚持:
const generateKey = (x) => {
return "" + x;
}
(如果两个列表可能具有相同的名称,那么将 Lists 索引作为键可能是个好主意。)
虽然这可行,但现在实际上很难存储状态,因为它被分成多个组件。因此,您可能希望“提升状态”,以便在父级中管理所有列表,并且每个更改都会传播到该父级:
class ToDoLists extends React.Component {
constructor(props) {
super(props);
this.state = { lists: [] };
}
updateList(old, updated) {
this.setState(({ lists }) => ({ lists: lists.map(l => l === old ? updated : l) }));
}
render() { return this.state.lists.map(list => <List list={list} onChange={updated => this.updateList(list, updated)} />); }
}
class List extends React.Component {
onSubmit() {
const { onChange, list } = this.props;
this.setState({ term: "" });
onChange([...list, this.state.term]);
}
//...
}
推荐阅读
- copy - 从 2 个工作表到列范围末尾的 Vba 到 vlookup
- database - 强制参照完整性(无级联选项)MS Access 与 MS SQL Server
- laravel - Laravel/Vue Carousel 正在工作,但无法更改循环、项目、自动播放等选项,因为未声明模块“vue-carousel”
- python - TypeError:在文本转换后运行随机森林分类器时,“int”和“str”的实例之间不支持“<”
- vb.net - 悬停在子控件上时如何避免触发 MouseLeave 事件?
- python - 如何根据分类变量对 pandas 数据框进行切片 - ei Country
- hash - 关于维基百科上对哈希函数的测试和测量的解释
- python - 如何在 pybullet 中更改 GUI?
- sql - 排除组 SQL Teradata 中特定列值之前的行
- javascript - 如何在 UseEffect 中的数组内映射数组