我正在学习 React.js ,但遇到了一个非常奇怪的问题。我逐步按照本教程进行操作,当我调用this.setState
用修改后的对象更新this.state
对象中的笑话数组时,它不会改变。我想在复选框单击时将completed
属性切换为true
/ false
。没有控制台错误。
欢迎任何意见。
JokesTemplate.js
function JokeTemplate(props){
return (
<div className="col-md-4">
<label>Joke {props.item.id}</label>
<p>Question {props.item.desc}</p>
<p>Answer: {props.item.ans}</p>
<input type="checkbox" checked={props.item.completed} onChange={() => props.handleChange(props.item.id)} />
</div>
);
}
export default JokeTemplate;
Jokes.js
import React from 'react';
import JokeTemplate from './JokeTemplate';
const jokes = [{
id:1,
desc: "Question 1",
ans: "Answer 1",
completed: false
},
{
id:2,
desc: "Question 2",
ans: "Answer 2",
completed: true
},
{
id:3,
desc: "Question 3",
ans: "Answer 3",
completed: false
}];
class Jokes extends React.Component{
constructor(){
super()
this.state = {
jokesLst: jokes
}
this.handleChange = this.handleChange.bind(this);
}
handleChange(id){
this.setState(prevState => {
let updatedObj = prevState.jokesLst.map( item =>{
if(item.id === id){
item.completed = !item.completed;
}
return item;
})
return { jokesLst: updatedObj }
});
}
render(){
const jokesComponentArr = this.state.jokesLst.map( joke => <JokeTemplate key={joke.id} item={joke} handleChange={this.handleChange} />);
return (
<>
{jokesComponentArr}
</>
)
}
}
export default Jokes;
App.js
import React from 'react';
import logo from './logo.svg';
import './App.css';
import NavBar from './components/NavBar';
import Jokes from './components/Jokes';
function App() {
return (
<div className="App">
<NavBar />
<header className="App-header">
<Jokes />
</header>
</div>
);
}
export default App;
谢谢。
答案 0 :(得分:1)
似乎您的代码仍在修改数组中的原始元素,因为它们是没有被值引用的对象。要消除此问题,您需要在.map()
内的回调中复制prevState
调用中的每个元素。
在handleChange
中,您可以尝试以下操作:
this.setState(prevState => {
let updatedObj = prevState.jokesLst.map(item => {
const newItem = { ...item }
if (newItem.id === id) {
newItem.completed = !newItem .completed
}
return newItem
})
return { jokesLst: updatedObj }
})
通过上面的额外const newItem = { ...item }
行查看区别。
或者您可以使用更短的时间:
this.setState(prevState => ({
...prevState,
jokesLst: prevState.jokesLst.map(item => ({
...item,
completed: item.id === id ? !item.completed : item.completed
}))
})
答案 1 :(得分:0)
我认为您只需要在Jokes.js内的handleChange()方法上进行修改
我从未见过在this.setState()方法内部放置逻辑来过滤“项目”并修改其“完成”字段的方法。但我建议您这样做。因此,在这里我们创建一个updatedObj的新实例,执行用于处理完成字段的所有逻辑。然后最终只需调用setState并将updatedObj直接传递给它即可。我在codeandbox上对此进行了测试,并且可以正常工作。
This is your logo
![Some option text][logo]
[logo]: {{ $logo }} "Logo"