ReactJS:在子组件内的父级上设置状态

IT技术 reactjs
2021-04-04 04:54:08

从子组件对父组件执行 setState 的推荐模式是什么。

var Todos = React.createClass({
  getInitialState: function() {
    return {
      todos: [
        "I am done",
        "I am not done"
      ]
    }
  },

  render: function() {
    var todos = this.state.todos.map(function(todo) {
      return <div>{todo}</div>;
    });

    return <div>
      <h3>Todo(s)</h3>
      {todos}
      <TodoForm />
    </div>;
  }
});

var TodoForm = React.createClass({
  getInitialState: function() {
    return {
      todoInput: ""
    }
  },

  handleOnChange: function(e) {
    e.preventDefault();
    this.setState({todoInput: e.target.value});
  },

  handleClick: function(e) {
    e.preventDefault();
    //add the new todo item
  },

  render: function() {
    return <div>
      <br />
      <input type="text" value={this.state.todoInput} onChange={this.handleOnChange} />
      <button onClick={this.handleClick}>Add Todo</button>
    </div>;
  }
});

React.render(<Todos />, document.body)

我有一组在父状态中维护的待办事项。我想访问父级的状态并从TodoFormhandleClick组件中添加一个新的待办事项我的想法是在父级上做一个 setState,它将呈现新添加的 todo 项。

6个回答

在您的父组件中,您可以创建一个函数addTodoItem,它会执行所需的 setState,然后将该函数作为props传递给子组件。

var Todos = React.createClass({

  ...

  addTodoItem: function(todoItem) {
    this.setState(({ todos }) => ({ todos: { ...todos, todoItem } }));
  },

  render: function() {

    ...

    return <div>
      <h3>Todo(s)</h3>
      {todos}
      <TodoForm addTodoItem={this.addTodoItem} />
    </div>
  }
});

var TodoForm = React.createClass({
  handleClick: function(e) {
    e.preventDefault();
    this.props.addTodoItem(this.state.todoInput);
    this.setState({todoInput: ""});
  },

  ...

});

您可以addTodoItem在 TodoForm 的 handleClick 中调用这将在父项上执行 setState ,它将呈现新添加的待办事项项。希望你能明白。

在这里摆弄。

this.state直接变异是不好的做法最好使用函数式 setState。reactjs.org/docs/react-component.html#setstate
2021-06-07 04:54:08
小提琴坏了
2021-06-07 04:54:08
什么是<<在运营商this.state.todos << todoItem;在这里做什么?
2021-06-10 04:54:08
这个(更新的)解决方案将如何使用 React 钩子实现?
2021-06-13 04:54:08
@zavtra 我猜小Ruby的混乱还在继续
2021-06-20 04:54:08

这些基本上都是正确的,我只是想我会指出新的(ish)官方react文档,它基本上推荐:-

对于在 React 应用程序中更改的任何数据,都应该有一个“真实来源”。通常,状态首先添加到需要它进行渲染的组件中。然后,如果其他组件也需要它,您可以将它提升到它们最近的共同祖先。您应该依赖自上而下的数据流,而不是尝试在不同组件之间同步状态。

请参阅https://reactjs.org/docs/lifting-state-up.html该页面还通过一个示例工作。

对于那些使用 React Hook 保持状态的人useState,我调整了上面的建议,在下面制作了一个演示滑块应用程序。在演示应用程序中,子滑块组件维护父组件的状态。

该演示还使用了useEffect钩子。(不太重要的是,useRef钩子)

import React, { useState, useEffect, useCallback, useRef } from "react";

//the parent react component
function Parent() {

  // the parentState will be set by its child slider component
  const [parentState, setParentState] = useState(0);

  // make wrapper function to give child
  const wrapperSetParentState = useCallback(val => {
    setParentState(val);
  }, [setParentState]);

  return (
    <div style={{ margin: 30 }}>
      <Child
        parentState={parentState}
        parentStateSetter={wrapperSetParentState}
      />
      <div>Parent State: {parentState}</div>
    </div>
  );
};

//the child react component
function Child({parentStateSetter}) {
  const childRef = useRef();
  const [childState, setChildState] = useState(0);

  useEffect(() => {
    parentStateSetter(childState);
  }, [parentStateSetter, childState]);

  const onSliderChangeHandler = e => {
  //pass slider's event value to child's state
    setChildState(e.target.value);
  };

  return (
    <div>
      <input
        type="range"
        min="1"
        max="255"
        value={childState}
        ref={childRef}
        onChange={onSliderChangeHandler}
      ></input>
    </div>
  );
};

export default Parent;
您可以将这个应用程序与 create-react-app 一起使用,并将 App.js 中的所有代码替换为上面的代码。
2021-05-22 04:54:08
@GLAND_PROPRE 我的回答本来可以更清楚:没有useEffect必要。我们可以直接setParentState(e.target.value)onSliderChangeHandler函数内部调用
2021-05-31 04:54:08
这些示例并不是为了说明为什么我们需要在父级和子级中存储数据——大多数时候你不需要。但是,如果您发现自己处于孩子应该设置父状态的情况,那么您可以这样做。如果要将父状态设置为 childState 更改的效果,则 useEffect 是必要的。
2021-06-10 04:54:08
@IanDunn 我相信useCallback可以防止在每次渲染时创建新函数。这里有一个很好的解释,说明什么时候需要,什么时候不需要。dmitripavlutin.com/dont-overuse-react-usecallback
2021-06-14 04:54:08
嗨,我刚开始反应,想知道:有必要使用useEffect吗?为什么我们需要将数据同时存储在父状态和子状态中?
2021-06-18 04:54:08

您可以在父组件中创建一个 addTodo 函数,将其绑定到该上下文,将其传递给子组件并从那里调用它。

// in Todos
addTodo: function(newTodo) {
    // add todo
}

然后,在 Todos.render 中,你会做

<TodoForm addToDo={this.addTodo.bind(this)} />

在 TodoForm 中调用它

this.props.addToDo(newTodo);
这太有用了。bind(this)在传递函数时没有做,它抛出错误 no such function this.setState is not a function
2021-06-17 04:54:08
parentSetState={(obj) => { this.setState(obj) }}
虽然此代码可能会回答问题,但提供有关如何和/或为什么解决问题的附加上下文将提高​​答案的长期value。
2021-06-15 04:54:08