数组映射函数未 return 更新项目

Array map function not return updated items

我遇到了一个奇怪的问题(至少对我来说是这样),其中 JS 数组方法 map() 没有 return 根据地图回调逻辑更新数组。 我有以下功能

1  handleChange (id){
2     this.setState((prevState)=>{
3      const todos = prevState.myTodos.map(item => {
4        if(item.id === id){
5          //console.log("ITEM.id is ",item.id,"id passed is ",id,"status is ",item.completed)
6          item.completed = !item.completed
7        }
8        //console.log("ITEM.id is ",item.id,"id passed was ",id,"new status is ",item.completed)
9        return item
10      })
11      return {myTodos : todos}
12    })
13  }

在这个函数中,我正在更新 App 对象的状态。 就在第 8 行的 return 项目之前,我可以记录输出并看到 item.completed 已更改但是当回调 returns 项目对象时,它不会将更新的项目存储在 todos变量。

任何提示都会有很大帮助。 感谢期待

完整代码如下: App.js 组件

import React from 'react';
//Importing components
import Todo from './components/Todo';

import './App.css';
//import todosData from './todosData';
const todosData=[  {
      id:1,
      text:"Take out the trash",
      completed:true,
      imageUrl : "https://environmentamerica.org/sites/environment/files/w-takeout-trash-wk1003mike-shutterstock_422191876.jpg"
  },
  {
      id:2,
      text:"Grocery Shopping",
      completed:false,
      imageUrl : "https://upload.wikimedia.org/wikipedia/commons/thumb/1/13/Supermarkt.jpg/240px-Supermarkt.jpg"

  },
  {
      id:3,
      text:"Clean gecko tank",
      completed:false,
      imageUrl : "https://i.ytimg.com/vi/hy7eLGcCU9Q/hqdefault.jpg"
  },
  {
      id:4,
      text:"Mow Lawn",
      completed:true,
      imageUrl : "https://cdn.theatlantic.com/thumbor/hbIVuzfmIWAZZ_zKMj1CKSeMkAM=/507x56:2754x1320/720x405/media/img/mt/2016/07/RTR20MER/original.jpg"
  }
];

class App extends React.Component {
  constructor(){
    super()
    this.state={
      myTodos : todosData,
      counter : 1
    }
    this.handleClick = this.handleClick.bind(this)
    this.handleChange = this.handleChange.bind(this)
  }
  handleClick (){
    this.setState((prevState)=>{

      const counterUpdated = prevState.counter +1
      return {counter : counterUpdated}
      
    })
  }
  handleChange (id){
     this.setState((prevState,anything)=>{
      const todos = prevState.myTodos.map(item => {
        if(item.id === id){
          console.log("ITEM.id is ",item.id,"id passed is ",id,"status is ",item.completed)
          item.completed = !item.completed
        }
        console.log("ITEM.id is ",item.id,"id passed was ",id,"new status is ",item.completed)
        return item
      })
      return {myTodos : todos}
    })
  }
  render(){
    const todoItems = this.state.myTodos.map(item=> {return <Todo key={item.id} todo={item} handleChange={this.handleChange} />})
    return (
    <div className="App">
      <header className="App-header">
        React Course from vSchool. <button onClick={this.handleClick} >Counter {this.state.counter}</button>
      </header>
      <main className="todo-container">
        <div className="todo-list">
        {todoItems}
        </div>
      </main>
      <footer className="footer">This is copy right of no one except for images :)</footer>
      
      </div>

  );}
}
export default App;

待办事项组件:

import React, { useState } from 'react'

function Todo(props){
    const [width,setWidth]=useState(140);
    const [height,setHeight]=useState(85);
    return(
        <div className="todo-item">
            <p style={{display : 'none'}}>{props.todo.id}</p>
            <p>{props.todo.text}</p>
            <input type="checkbox" checked={props.todo.completed}
             
             onChange={()=>{props.handleChange(props.todo.id)}}
             
             />
            <img 
            // onMouseOver={(e)=>{setWidth(250);setHeight(250);}} 
            // onMouseOut={(e)=>{setWidth(140);setHeight(85);}}
            src={props.todo.imageUrl} width={width} height={height}/>
            <hr />
        </div>
    );
}
export default Todo;

您可以尝试使您的 if 条件内联,这样您就不会使用 return 。类似于:

handleChange (id){
    this.setState((prevState)=>{
    const todos = prevState.myTodos.map(item => 
            (item.id === id) ? {...item, completed: !item.completed} : item )
    })
}

已编辑:此解决方案之所以有效,是因为它 returns 使用扩展语法 {...item, completed: !item.completed} 的新 JS 对象。反过来,这会强制进行新的渲染调用。

请检查此代码段

import React, { Component } from "react";
import "./styles.css";

class App extends Component {
  state = {
    myTodos: [
      { id: 1, title: "wake up", completed: false },
      { id: 2, title: "brush", completed: false }
    ]
  };

  handleChange = (id) => {
    this.setState((prevState) => ({
      myTodos: prevState.myTodos.map((todo) => {
        if (todo.id === id) {
          return { ...todo, completed: !todo.completed };
        }
        return todo;
      })
    }));
  };

  render() {
    return (
      <div className="App">
        <h1>TODOS</h1>
        {this.state.myTodos.map((todo) =>
          todo.completed ? (
            <del>
              <p onClick={() => this.handleChange(todo.id)}>{todo.title}</p>
            </del>
          ) : (
            <p onClick={() => this.handleChange(todo.id)}>{todo.title}</p>
          )
        )}
      </div>
    );
  }
}

export default App;

工作 codesandbox

问题:

  1. 您没有返回真实条件下的对象