反应–将表单元素状态传递给同级/父元素的正确方法?

reactjs React.js

神无LEY

2020-03-11

  • 假设我有一个React类P,它渲染了两个子类C1和C2。
  • C1包含一个输入字段。我将此输入字段称为Foo。
  • 我的目标是让C2对Foo的变化做出反应。

我已经提出了两种解决方案,但是它们都不对。

第一个解决方案:

  1. 为P分配一个状态,state.input
  2. onChange在P中创建一个函数,该函数接受一个事件并设置state.input
  3. onChange将其作为传递给C1 props,然后让C1绑定this.props.onChangeonChangeFoo。

这可行。每当Foo的值更改时,它都会触发setStateP中的a,因此P会将输入传递给C2。

但是由于相同的原因,感觉不太正确:我正在从子元素中设置父元素的状态。这似乎背叛了React的设计原理:单向数据流。
这是我应该怎么做,还是有一个更自然的React解决方案?

第二种解决方案:

只需将Foo放在P中即可。

但这是我在构建应用程序时应遵循的设计原则—将所有表单元素都放在render最高级别的类中?

就像在我的示例中一样,如果我渲染了很大的C1,我真的不想仅将renderC1 放在renderP中就因为C1具有表单元素。

我该怎么办?

第572篇《反应–将表单元素状态传递给同级/父元素的正确方法?》来自Winter(https://github.com/aiyld/aiyld.github.io)的站点

5个回答
LEY神无 2020.03.11

我很惊讶,在我撰写本文时,没有一个简单的惯用React解决方案的答案。所以这是一个(将大小和复杂度与其他进行比较):

class P extends React.Component {
    state = { foo : "" };

    render(){
        const { foo } = this.state;

        return (
            <div>
                <C1 value={ foo } onChange={ x => this.setState({ foo : x })} />
                <C2 value={ foo } />
            </div>
        )
    }
}

const C1 = ({ value, onChange }) => (
    <input type="text"
           value={ value }
           onChange={ e => onChange( e.target.value ) } />
);

const C2 = ({ value }) => (
    <div>Reacting on value change: { value }</div>
);

我正在从子元素设置父元素的状态。这似乎背叛了React的设计原理:单向数据流。

任何受控的input(在React中使用表单的惯用方式)都会在其onChange回调中更新父状态,并且仍然不会出卖任何东西。

例如,仔细查看C1组件。您是否看到C1内置input组件处理状态更改的方式有何重大不同您不应该,因为没有。对于原始React来说,提升状态并传递值/ onChange对是惯用的。如某些答案所示,不使用裁判。

阳光猿 2020.03.11

解释了将数据从父级传递到子级,反之亦然的概念。

import React, { Component } from "react";
import ReactDOM from "react-dom";

// taken refrence from https://gist.github.com/sebkouba/a5ac75153ef8d8827b98

//example to show how to send value between parent and child

//  props is the data which is passed to the child component from the parent component

class Parent extends Component {
  constructor(props) {
    super(props);

    this.state = {
      fieldVal: ""
    };
  }

  onUpdateParent = val => {
    this.setState({
      fieldVal: val
    });
  };

  render() {
    return (
      // To achieve the child-parent communication, we can send a function
      // as a Prop to the child component. This function should do whatever
      // it needs to in the component e.g change the state of some property.
      //we are passing the function onUpdateParent to the child
      <div>
        <h2>Parent</h2>
        Value in Parent Component State: {this.state.fieldVal}
        <br />
        <Child onUpdate={this.onUpdateParent} />
        <br />
        <OtherChild passedVal={this.state.fieldVal} />
      </div>
    );
  }
}

class Child extends Component {
  constructor(props) {
    super(props);

    this.state = {
      fieldValChild: ""
    };
  }

  updateValues = e => {
    console.log(e.target.value);
    this.props.onUpdate(e.target.value);
    // onUpdateParent would be passed here and would result
    // into onUpdateParent(e.target.value) as it will replace this.props.onUpdate
    //with itself.
    this.setState({ fieldValChild: e.target.value });
  };

  render() {
    return (
      <div>
        <h4>Child</h4>
        <input
          type="text"
          placeholder="type here"
          onChange={this.updateValues}
          value={this.state.fieldVal}
        />
      </div>
    );
  }
}

class OtherChild extends Component {
  render() {
    return (
      <div>
        <h4>OtherChild</h4>
        Value in OtherChild Props: {this.props.passedVal}
        <h5>
          the child can directly get the passed value from parent by this.props{" "}
        </h5>
      </div>
    );
  }
}

ReactDOM.render(<Parent />, document.getElementById("root"));

猴子Sam 2020.03.11

您应该学习Redux和ReactRedux库。它将在一个商店中构造您的状态和道具,您以后可以在组件中访问它们。

神无LEY 2020.03.11

在使用React现在构建应用程序之后,我想分享我半年前提出的这个问题的一些想法。

我建议你阅读

第一篇文章对理解如何构建React应用程序非常有帮助。

Flux回答了一个问题,为什么您应该以这种方式构建React应用程序(而不是如何构建它)。React仅占系统的50%,通过Flux,您可以看到整个图片,并了解它们如何构成一个连贯的系统。

回到问题。

对于我的第一个解决方案,完全可以让处理程序反向运行,因为数据仍在单向运行。

但是,根据您的情况,让处理程序触发P中的setState可能是对还是错。

如果应用程序是一个简单的Markdown转换器,C1是原始输入,C2是HTML输出,那么让C1触发P中的setState是可以的,但是有些人可能会认为这不是推荐的方法。

但是,如果应用程序是待办事项列表,C1是创建新待办事项的输入,C2是HTML中的待办事项列表,则您可能希望将处理程序比P-上移两个级别dispatcher,从而storedata store,然后将数据发送到P并填充视图。看到该助焊剂文章。这是一个示例:Flux-TodoMVC

通常,我更喜欢待办事项列表示例中描述的方法。应用程序中的状态越少越好。

Stafan路易 2020.03.11

状态保留在父组件中的第一个解决方案正确的但是,对于更复杂的问题,您应该考虑一些状态管理库redux是与react一起使用的最流行的一种。

问题类别

JavaScript Ckeditor Python Webpack TypeScript Vue.js React.js ExpressJS KoaJS CSS Node.js HTML Django 单元测试 PHP Asp.net jQuery Bootstrap IOS Android