javascript - 状态更改后子组件不更新

标签 javascript reactjs

我正在学习 React,并且正在制作一个简单的 ToDoApp。我在应用程序组件的状态下从 JSON 文件设置了一些待办事项数据,并使用这些值填充子组件。我编写了一个方法,每次在复选框元素上触发 onChange 事件时都会调用该方法,并通过更新状态来翻转复选框。问题是这段代码以前工作得很好,但现在不行了。当我更改复选框时,状态会相应更新,但它不会在子元素中更新,我想知道为什么。这是我的代码

App.js

import React from "react";
import TodoItem from "./TodoItem";
import toDoData from "./toDosData";

class App extends React.Component {
    constructor() {
        super();
        this.state = {
            toDoData: toDoData
        };
        this.handleOnChange = this.handleOnChange.bind(this);
    }

    handleOnChange(key)
    {
        this.setState(prevState => {
            let newState = prevState.toDoData.map(currentData => {
                if(currentData.id === key)
                    currentData.completed = !currentData.completed;
                return currentData;
            });
            return {toDoData: newState};
        });
    }

    render() {
        let toDoComponents = this.state.toDoData.map(toDoDatum =>
            <TodoItem key={toDoDatum.id} details={{
                key: toDoDatum.id,
                text: toDoDatum.text,
                completed: toDoDatum.completed,
                onChange: this.handleOnChange
            }} />);
        return (
            <div>
                {toDoComponents}
            </div>
        );
    }
}

export default App;

TodoItem.js

import React from "react";

class TodoItem extends React.Component {

    properties = this.props.details;

    render() {
        return (
            <div>
                <input type="checkbox" checked={this.properties.completed}
                    onChange={() => this.properties.onChange(this.properties.key)}
                />
                <span>{this.properties.text}</span>
            </div>
        )
    }
}

export default TodoItem;

提前致谢。

最佳答案

为什么需要将 details 属性分配给类中的 properties ?如果您这样做,properties 不会反射(reflect) prop 更改,并且您的子组件将无法看到更新。只需按原样使用 Prop 即可:

render() {
  const { details } = this.props;
  return (
    <div>
      <input
        type="checkbox"
        checked={details.completed}
        onChange={() => details.onChange(details.key)}
      />
      <span>{details.text}</span>
    </div>
  );
}
}

此外,由于您在 TodoItem 组件中不使用任何状态或生命周期方法,因此它也可以是一个功能组件。

const TodoItem = ({ details }) => (
  <div>
    <input
      type="checkbox"
      checked={details.completed}
      onChange={() => details.onChange(details.key)}
    />
    <span>{details.text}</span>
  </div>
);

还有一件事,为什么不直接将 todo 本身传递给 TodoItem 呢?

<TodoItem
  key={toDoDatum.id}
  todo={toDoDatum}
  onChange={this.handleOnChange}
/>

const TodoItem = ({ todo, onChange }) => (
  <div>
    <input
      type="checkbox"
      checked={todo.completed}
      onChange={() => onChange(todo.id)}
    />
    <span>{todo.text}</span>
  </div>
);

这不是更具可读性吗?

评论后更新

const toDoData = [
  { id: 1, text: "foo", completed: false },
  { id: 2, text: "bar", completed: false },
  { id: 3, text: "baz", completed: false }
];

const TodoItem = ({ todo, onChange }) => (
  <div>
    <input
      type="checkbox"
      checked={todo.completed}
      onChange={() => onChange(todo.id)}
    />
    <span>{todo.text}</span>
  </div>
);

class App extends React.Component {
  constructor() {
    super();
    this.state = {
      toDoData: toDoData
    };
    this.handleOnChange = this.handleOnChange.bind(this);
  }

  handleOnChange(key) {
    this.setState(prevState => {
      let newState = prevState.toDoData.map(currentData => {
        if (currentData.id === key)
          currentData.completed = !currentData.completed;
        return currentData;
      });
      return { toDoData: newState };
    });
  }

  render() {
    let toDoComponents = this.state.toDoData.map(toDoDatum => (
      <TodoItem
        key={toDoDatum.id}
        todo={toDoDatum}
        onChange={this.handleOnChange}
      />
    ));
    return <div>{toDoComponents}</div>;
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root" />

关于javascript - 状态更改后子组件不更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56589261/

相关文章:

javascript - li 背景颜色重复/图案

php - 在 PHP 中获取 Json 表单数据

java - 发布开关输入 boolean 值(React/Typescript)

reactjs - jest.mock(module) 和 jest.fn() 有什么区别

html - React.Js/ typescript : How can I pass colors through props?

javascript - jQuery Datepicker,在同一页面上显示2个不同的日期选择器

javascript - 这是一个很好的 javascript 装饰器模式吗?

javascript - Jquery - JavaScript - mouseleave 忽略 "toElement"属性的 child

javascript - 结合静态站点 + 客户端渲染(React、Gatsby)

javascript - 使用 React 从多个文件调用变量?