【问题标题】:React.js setState issueReact.js setState 问题
【发布时间】:2020-10-26 11:41:22
【问题描述】:

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

提前致谢。

【问题讨论】:

    标签: javascript reactjs setstate


    【解决方案1】:

    您的代码似乎仍在修改数组中的原始元素,因为它们是未被值引用的对象。要消除此问题,您需要在 prevState 内的回调中复制 .map() 调用中的每个元素。

    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
       }))
    })
    

    【讨论】:

    • 是的,它有效,但为什么它需要newItem,据我所知,map() 函数映射数组中的每个项目,我们可以使用点访问每个属性。我也试过forEach(),但它没有用。你能解释一下吗?
    • @MariosNikolaou 从技术上讲,.map() 创建了一个新数组,这是真的,请参阅文档:map() 方法创建一个新数组,其中填充了在每个元素上调用提供的函数的结果在调用数组中。 但是元素内部仍然具有原始引用,这就是您需要复制它们的原因。我希望这可以澄清!
    • 如果我使用foreach(),它会和map()一样吗?
    • 同样在.forEach()还需要复制里面的元素。也不要忘记.forEach() 不返回任何东西,不像.map(),请参阅文档:forEach() 方法为每个数组元素执行一次提供的函数。.
    【解决方案2】:

    我认为你只需要修改 Jokes.js 中的 handleChange() 方法

    我从未见过这种将逻辑过滤“项目”并在 this.setState() 方法中修改其“已完成”字段的方式。但我建议你这样做。所以在这里我们创建了一个新的updatedObj实例,完成了操作完成字段的所有逻辑。然后最后只需调用 setState 并将 updatedObj 直接传递给它。我在codesandbox上测试过,效果很好。

    handleChange(id) {
       let updatedObj = this.state.jokesLst.map((item) => {
          if (item.id === id) {
            item.completed = !item.completed;
          }
        
          return item;
        });
        
        this.setState({
          jokesLst: updatedObj
        });
       };
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-12-03
      • 2014-11-17
      • 1970-01-01
      • 2016-02-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-05
      相关资源
      最近更新 更多