React.js setState问题

时间:2020-10-26 11:41:22

标签: javascript reactjs setstate

我正在学习 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;

谢谢。

2 个答案:

答案 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"