通过对象扩展器更改状态时不会重新渲染

发布于 2025-01-15 17:43:16 字数 5219 浏览 1 评论 0原文

我目前正在尝试清理我的 Todo 应用程序的代码并使用更多的不变性。因此,我替换了handleStatus函数中的代码。

从此:

 handleStatus(event) {
      let newStatus;
      const changeState = event.status == 'done' ? newStatus = 'open' : newStatus = 'done';
      
      //Verkürzen Copy State
      let todo = event;
      todo.status = newStatus;

      this.setState({ todo });
     
    }

到此:

 handleStatus(event) {
      let newStatus;
      const changeState = event.status == 'done' ? newStatus = 'open' : newStatus = 'done';
      
      //Verkürzen Copy State
      let todo = {
        ...event,
        status: newStatus
      };

      this.setState({ todo });
     
    }

各个待办事项的状态发生了更改,但 React 不再渲染相应的部分,因此浏览器中不会发生任何更改。

感谢您的帮助

这是完整的代码...... TodoTable(父母):

import React from "react";
import { InputBar } from "./InputBar";
import { Todo } from "./Todo";

const emptyForm = {
  enterTodo: ""
  
};

export class TodoTable extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
        enterTodo: "",
        todos: this.props.todos,
        status: 'open'
      };
      this.handleEnterTodo = this.handleEnterTodo.bind(this);
      this.handleStatus = this.handleStatus.bind(this);
      this.handleCreateTodo = this.handleCreateTodo.bind(this);
      this.handleClearTodos = this.handleClearTodos.bind(this);
      this.handleDeleteTodo = this.handleDeleteTodo.bind(this);
 
    }
    //Textbox Input handler
    handleEnterTodo(event) {
      
      this.setState({
        enterTodo: event.target.value
      });
    }
    //Status handler
    handleStatus(event) {
      let newStatus;
      const changeState = event.status == 'done' ? newStatus = 'open' : newStatus = 'done';
      
      //Verkürzen Copy State
      let todo = {
        ...event,
        status: newStatus
      };

      this.setState({ todo });
     
    }

    //delete todo
    handleDeleteTodo(event) {
      let todo = this.state.todos;
      todo.splice(this.state.todos.indexOf(event), 1)
    
      this.setState({ todo });
    }
   
    //Create Todo
    handleCreateTodo(event) {
      const todo = {
        id: this.state.todos.length,
        describtion: this.state.enterTodo,
        status: 'open'
      };

        this.setState({
          todos: [todo, ...this.state.todos]
        })
        this.state.enterTodo = emptyForm.enterTodo; // Überarbeiten
      
    }

    //Clear Todo List 
    handleClearTodos(event) {
      let CleanedTodos = []
      
      this.state.todos.forEach((element, index) => {

        if(this.state.todos[index].status == 'open'){
            CleanedTodos.push(this.state.todos[index]);
        } 
        
      });

      this.setState({ 
        todos: CleanedTodos
       });
    }

    render() {

      return (

        <>
          <InputBar

            handleCreateTodo={ this.handleCreateTodo }
            handleEnterTodo={ this.handleEnterTodo }
            enterTodo={ this.state.enterTodo }
            handleClearTodos={ this.handleClearTodos }
          />
          <Todo

            handleStatus={ this.handleStatus }
           
            todos={ this.state.todos }
            handleClearTodos={ this.state.handleClearTodos }
            handleDeleteTodo= { this.handleDeleteTodo }
          />
        </>
      );
    }
  }

Todo(孩子);

import React from "react";
import { FormButton } from "./FormButton";


export class Todo extends React.Component {
    render() {
      const openTodo = [];
      const doneTodo = [];
      // just for develope
      const lineBreak = <hr></hr>
      

      //Select Open Todo and Done
      this.props.todos.forEach((element, index) => {
        if(this.props.todos[index].status == 'open'){
    
          let todoOpen = (
            //CSS Clases for design open 
            <div className="openTodos" key={this.props.todos[index].id.toString() }>
              
              {this.props.todos[index].describtion}
              <FormButton lable='' onClick= {() => this.props.handleStatus(this.props.todos[index])}/>
              <FormButton lable='' onClick= {() => this.props.handleDeleteTodo(this.props.todos[index])}/>
          
            </div>
          );
          //Push open Todo in Open Array
          openTodo.push(todoOpen); 
        } 
        else{
         
          let todoDone = (
            //CSS Clases for design open 
            <div className="openTodos" key={this.props.todos[index].id.toString() }>
          
              {this.props.todos[index].describtion}
              <FormButton lable='' onClick= {() => this.props.handleStatus(this.props.todos[index])}/>
              <FormButton lable='' onClick= {() => this.props.handleDeleteTodo(this.props.todos[index])}/>
      
            </div>
          );
          //Push done Todo in Done Array
          doneTodo.push(todoDone); 
        }

      });
      
      return <>
              {openTodo}
              {lineBreak}
              {doneTodo}
            </>;
    }
  }

I am currently trying to clean up the code of my Todo app a bit and use more immutability. I have therefore replaced the code in the handleStatus function.

From this:

 handleStatus(event) {
      let newStatus;
      const changeState = event.status == 'done' ? newStatus = 'open' : newStatus = 'done';
      
      //Verkürzen Copy State
      let todo = event;
      todo.status = newStatus;

      this.setState({ todo });
     
    }

To this:

 handleStatus(event) {
      let newStatus;
      const changeState = event.status == 'done' ? newStatus = 'open' : newStatus = 'done';
      
      //Verkürzen Copy State
      let todo = {
        ...event,
        status: newStatus
      };

      this.setState({ todo });
     
    }

The status of the respective todo is changed but React no longer renders the corresponding part so that no change takes place in the browser.

Thank you for help

Here is the Full Code....
TodoTable (Parents):

import React from "react";
import { InputBar } from "./InputBar";
import { Todo } from "./Todo";

const emptyForm = {
  enterTodo: ""
  
};

export class TodoTable extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
        enterTodo: "",
        todos: this.props.todos,
        status: 'open'
      };
      this.handleEnterTodo = this.handleEnterTodo.bind(this);
      this.handleStatus = this.handleStatus.bind(this);
      this.handleCreateTodo = this.handleCreateTodo.bind(this);
      this.handleClearTodos = this.handleClearTodos.bind(this);
      this.handleDeleteTodo = this.handleDeleteTodo.bind(this);
 
    }
    //Textbox Input handler
    handleEnterTodo(event) {
      
      this.setState({
        enterTodo: event.target.value
      });
    }
    //Status handler
    handleStatus(event) {
      let newStatus;
      const changeState = event.status == 'done' ? newStatus = 'open' : newStatus = 'done';
      
      //Verkürzen Copy State
      let todo = {
        ...event,
        status: newStatus
      };

      this.setState({ todo });
     
    }

    //delete todo
    handleDeleteTodo(event) {
      let todo = this.state.todos;
      todo.splice(this.state.todos.indexOf(event), 1)
    
      this.setState({ todo });
    }
   
    //Create Todo
    handleCreateTodo(event) {
      const todo = {
        id: this.state.todos.length,
        describtion: this.state.enterTodo,
        status: 'open'
      };

        this.setState({
          todos: [todo, ...this.state.todos]
        })
        this.state.enterTodo = emptyForm.enterTodo; // Überarbeiten
      
    }

    //Clear Todo List 
    handleClearTodos(event) {
      let CleanedTodos = []
      
      this.state.todos.forEach((element, index) => {

        if(this.state.todos[index].status == 'open'){
            CleanedTodos.push(this.state.todos[index]);
        } 
        
      });

      this.setState({ 
        todos: CleanedTodos
       });
    }

    render() {

      return (

        <>
          <InputBar

            handleCreateTodo={ this.handleCreateTodo }
            handleEnterTodo={ this.handleEnterTodo }
            enterTodo={ this.state.enterTodo }
            handleClearTodos={ this.handleClearTodos }
          />
          <Todo

            handleStatus={ this.handleStatus }
           
            todos={ this.state.todos }
            handleClearTodos={ this.state.handleClearTodos }
            handleDeleteTodo= { this.handleDeleteTodo }
          />
        </>
      );
    }
  }

Todo (Child);

import React from "react";
import { FormButton } from "./FormButton";


export class Todo extends React.Component {
    render() {
      const openTodo = [];
      const doneTodo = [];
      // just for develope
      const lineBreak = <hr></hr>
      

      //Select Open Todo and Done
      this.props.todos.forEach((element, index) => {
        if(this.props.todos[index].status == 'open'){
    
          let todoOpen = (
            //CSS Clases for design open 
            <div className="openTodos" key={this.props.todos[index].id.toString() }>
              
              {this.props.todos[index].describtion}
              <FormButton lable='' onClick= {() => this.props.handleStatus(this.props.todos[index])}/>
              <FormButton lable='' onClick= {() => this.props.handleDeleteTodo(this.props.todos[index])}/>
          
            </div>
          );
          //Push open Todo in Open Array
          openTodo.push(todoOpen); 
        } 
        else{
         
          let todoDone = (
            //CSS Clases for design open 
            <div className="openTodos" key={this.props.todos[index].id.toString() }>
          
              {this.props.todos[index].describtion}
              <FormButton lable='' onClick= {() => this.props.handleStatus(this.props.todos[index])}/>
              <FormButton lable='' onClick= {() => this.props.handleDeleteTodo(this.props.todos[index])}/>
      
            </div>
          );
          //Push done Todo in Done Array
          doneTodo.push(todoDone); 
        }

      });
      
      return <>
              {openTodo}
              {lineBreak}
              {doneTodo}
            </>;
    }
  }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

傻比既视感 2025-01-22 17:43:16

问题是您没有更新 todos 状态。您的状态在 TodoTable 构造函数中定义为:

this.state = {
   enterTodo: "",
   todos: this.props.todos,
   status: 'open'
};

但是您更新的状态是 todo,这是之前未分配的新状态属性。

this.setState({ todo });

在将 handleStatus 设为不可变之前,更改会起作用,因为您更改了实际的状态对象。然后在 this.setState({ todo }) 重新渲染组件后反映在 UI 中。

handleStatus 中已有的 todo 对象是 todos 数组中已更改的项目。现在,使用更改设置 todos 状态。

编辑:这是对handleStatus的彻底更改。我添加了评论来澄清我做了什么。有很多方法可以不可变地更改数组(您也可以拼接并通过索引查找,或映射一个新数组),我在这里建议一种方法。

handleStatus(changedTodo) {
   let newStatus = changedTodo.status == 'done' ? 'open' : 'done'; // It is more simple that way - you can assign newStatus directly.
   let todos = this.state.todos.slice(); // Create a copy of current state. A simple way to do immutable change.

   // Change todos state
   let todo = todos.find(i => i.id === changedTodo.id); // Find the changed object in the array

   if (todo) { // If object found, do the change
      todo = {
        ...todo,
        status: newStatus
      }
      this.setState({ todos }); // Update todos state
   }
}

The problem is that you do not update the todos state. Your state is defined in TodoTable constructor as:

this.state = {
   enterTodo: "",
   todos: this.props.todos,
   status: 'open'
};

But the state you update is todo, which is a new state property that wasn't assigned before.

this.setState({ todo });

Before you made handleStatus immutable, the change worked because you changed the actual state object. Then it was reflected in the UI after this.setState({ todo }) re-rendered the component.

todo object that you already have in handleStatus is the item in the todos array that has changed. Now, set the todos state with the changes.

Edit: here is a complete change in handleStatus. I added comments to clarify what I did. There are many ways to change an array immutably (you can also splice and find by index, or map a new array), I suggest here one way.

handleStatus(changedTodo) {
   let newStatus = changedTodo.status == 'done' ? 'open' : 'done'; // It is more simple that way - you can assign newStatus directly.
   let todos = this.state.todos.slice(); // Create a copy of current state. A simple way to do immutable change.

   // Change todos state
   let todo = todos.find(i => i.id === changedTodo.id); // Find the changed object in the array

   if (todo) { // If object found, do the change
      todo = {
        ...todo,
        status: newStatus
      }
      this.setState({ todos }); // Update todos state
   }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文