我正在看一个React教程,而讲师并没有很好地解释我理解的部分。他基本上是在尝试教如何在三个不同的输入框中动态呈现列表。在每个输入框中键入的内容都会渲染到其上方的相应div元素。并且讲师告诉我们,我们不应该直接触及该代码变得更加复杂的状态。有什么更简单的方法可以编写此代码?不了解他。讲师指示的代码在 nameChangeHandler 函数中。请参见下面的代码。谢谢!
import React, { Component } from 'react';
import './App.css';
import Person from "./Person/Person"
class App extends React.Component {
state={
persons: [
{id: 1,name: "Max", age:28 },
{id:2,name: "Manu", age: 29},
{id:3, name: "Stephanie", age: 26 }
],
showPersons: false
}
deletePersonHandler=(index)=> {
const persons = [...this.state.persons];
persons.splice(index, 1)
this.setState({ persons: persons});
console.log(persons)
}
nameChangedHandler = (e, id ) => {
const personIndex = this.state.persons.findIndex(p=> {
return p.id === id;
})
const person = {
...this.state.persons[personIndex]
};
person.name= e.target.value;
const persons = [...this.state.persons];
persons[personIndex] = person;
this.setState({
persons: persons
})
}
togglePersonsHandler=()=> {
const showing = this.state.showPersons;
this.setState({ showPersons: !showing })
}
render() {
const style={
backgroundColor: "white",
font:"inherit",
border:"1px solid blue",
padding:"8px",
cursor:"pointer"
}
let persons=null;
if(this.state.showPersons) {
persons=(
<div>
{this.state.persons.map((person, index)=> {
return(
<Person
key={person.id}
changed={(e)=>this.nameChangedHandler(e, person.id)}
click={()=>this.deletePersonHandler(index)}
name={person.name}
age={person.age}/>
)
})}
</div>)
}
return (
<div className="App">
<h1>Hi, Im a React App</h1>
<p>This is really working!!!</p>
<button style={style} onClick={this.togglePersonsHandler}>Toggle Persons</button>
{persons}
</div>
);
}
}
export default App;
答案 0 :(得分:1)
根据您在注释中的要求,此代码简要说明:
nameChangedHandler = (e, id ) => {
const personIndex = this.state.persons.findIndex(p=> {
return p.id === id;
})
您看到的是arrow function。出于整个答案的目的,请将它们视为正常函数(虽然不一样,但是也可以使用常规函数来完成)。从语义上讲,箭头函数或常规函数不会更改代码的用途/意图,因此我不再赘述,您应该只知道所看到的内容。如果您不熟悉它们,则应该仔细阅读,它们非常有用。箭头功能的签名为(a,b) => {}
,a => {}
或a => <expression>
。因此,粗略地说,以上内容在逻辑上可以解释为function(e,id){}
和function(p){}
,只是为了在我继续之前先搞清楚(如果以这种方式编写,它是行不通的,但这就是它传达的信息)。>
代码本身提取与您传递给nameChangeHandler的id
参数匹配的人员的索引。这是通过findIndex完成的,该函数会遍历数组(在本例中为状态的.persons
数组),并返回通过给定测试函数的第一个元素的索引。然后将该索引存储在变量中,以供以后在代码中使用。
e
和id
来自函数本身的调用,由于看不到<Person>
类是什么,因此我无法提供更多详细信息,但是这样做很安全假定此处理程序已附加到输入字段。通过输入字段上的onChange
处理程序发生更改后,react将触发一个处理程序并将包含事件数据的event
传递给它。您的处理程序实际上不是nameChangeHandler
函数,它是一个带event e
的箭头函数,然后调用nameChangeHandler
并传递event e
和{{ 1}},您可以在id
看到。其余的值则从您的changed={(e)=>this.nameChangedHandler(e, person.id)}
中读取。
让我们继续执行代码:
state
我们在这里称为spread。它本质上是“解压缩和重新打包”对象或数组,您可以在给定的MDN链接上了解有关它的更多信息。这是ES6的一项强大的新功能,使生活更加轻松。
因此,上述代码用于将数组中的人员对象巧妙地浅复制到新的局部变量中(或者更确切地说是const person = {
...this.state.persons[personIndex]
};
,因为变量将暗示有更改的可能)我们这样做是因为在javascript中,对象数据是按引用存储的,因此我们不能简单地更改初始数组内的person对象,这会使状态发生变化。我们不想改变国家。不变是关键。
const
下面有一个简单的任务。我们刚刚创建的新person.name= e.target.value;
对象是该州person
数组中的人的精确副本(某种形式),这不好,我们想要更改名称,所以我们做就是这样我们访问.persons
的{{1}}并读取触发它的event e
的{{1}},将新值分配给我们的value
对象,现在我们有了一个“改变的人”(双关语)。
剩下要做的是,将这些更改推入状态,以便新的渲染可以显示它们,所以我们这样做:
target
此代码再次使用 spread 来将旧阵列从状态克隆/复制到新的本地阵列人员中。它等效于使用person
。您可以在MDN上阅读有关const persons = [...this.state.persons];
persons[personIndex] = person;
的更多信息(有意不要为您留下直接链接,以便您搜索它并了解该部分,MDN确实是各种文档的绝佳来源并且了解您在该网站上的访问方式可以节省很多时间。)最后,克隆数组后,我们找到原始人,并用名称已更改的本地人对象替换它。
const persons = this.state.persons.slice()
最后,我们使用react提供的.slice()
方法(请参阅documentation)来不变地更改状态。此更改将触发一个新的this.setState({
persons: persons
})
,您将可以在UI中看到更改。 .setState
本身通过进行浅合并进行操作。这意味着仅将传递给方法本身的属性更改/添加到状态,其余属性将保持原样。由于我们传递的唯一内容是render()
的另一个数组,它是我们的本地数组,并且具有更改的人,因此唯一更改的是
答案 1 :(得分:0)
在基于当前本地状态更新本地状态时,由于React批处理this.setState
的调用方式,您应该使用setState回调模式。
此外,浅表复制和更新也很好,但是您也可以使用标准的Array.prototype.map
方法执行更新:
nameChangedHandler = (e, id ) => {
this.setState((prevState) => {
const persons = prevState.persons.map(person, i => {
return i === id ? { ...person, name: e.target.name } : person;
});
return {
persons: persons,
};
});
}
答案 2 :(得分:0)
import React, { Component} from 'react';
import './App.css';
import Person from './Person/Person';
class App extends Component{
state = {
persons : [
{id:1, name : 'sohan', age : 28},
{id:2, name : 'Rohan', age : 29},
{id:3, name : 'Stephani', age : 21}
],
otherState : 'hiii',
showPersons : false
}
nameChangeHandler = (event, id)=>{
const personInedex = this.state.persons.find(p => {
return p.id === id;
})
personInedex.name = event.target.value;
this.setState({persons:this.state.persons})
}
toglePerson = ()=>{
this.setState({showPersons:!this.state.showPersons})
}
delete = (item) =>{
const persons = [...this.state.persons];
persons.splice(item, 1);
this.setState({persons: persons});
}
render(){
const style = {
backgroundColor: '#88dc707d',
margin: 0,
font: 'inherit',
padding : '15px',
cursor: 'pointer',
color: 'white',
boxShadow: '15px 10px 12px grey',
borderRadius: '22px 5px 22px 5px'
}
let persons = null
if(this.state.showPersons){
persons = (
<div>
{this.state.persons.map((item, index) => {
return <Person key={item.id}
name={item.name}
age={item.age}
onchange={(event) => this.nameChangeHandler(event, item.id)}
deleteName={()=> this.delete(index)} />
})}
</div>
)
}
return (
<div className="App">
<h1> hii i am React App</h1>
<button
style={style}
onClick={this.toglePerson}>Togle Name</button>
{persons}
</div>
);
}
}
export default App;
// state = {
// persons : [
// {name : 'sohan', age : 28},
// {name : 'Rohan', age : 29},
// {name : 'Stephani', age : 21}
// ],
// otherState : 'hiii'
// }
// switchNameHandler = () => {
// console.log(this.state)
// this.setState({
// persons : [
// {name : 'Sudan Lal', age : 28},
// {name : 'Rohan', age : 29},
// {name : 'Stephani', age : 25}`enter code here`
// ]
// })
// }