组成和继承:在React中的组件之间共享逻辑

时间:2018-09-10 11:07:49

标签: reactjs forms composition

我对React中的继承和组合有疑问。

我习惯了Backbone,其中通常的过程是创建处理数据和渲染逻辑的类视图。当您有一些共享某些逻辑的组件(例如表单)时,可以对其进行抽象创建一个新组件(一个类),在其中添加共享的逻辑,然后从其他组件扩展该类。这样,最终将得到具有共享逻辑和扩展它的组件的抽象组件:

var generalForm = Backbone.View.extend({
    customMethod: function (){
        // Some shared logic
    }
});


var Form = generalForm.extend({
    // This class has customMethod from generalForm.
});

现在我看到React使用的是合成而不是继承。进行组合的方法有两种:包装组件或使用Higher-Order Components。为了使事情变得更容易,我对这两种可能性进行了沙盒测试:https://codesandbox.io/s/wyn629rm4l

进行合成的第一种方法是将一个组件包装在另一个组件中:

class Form extends Component {
  constructor(props) {
    super(props);
    this.state = {};
  }

  handleUpdate(e) {
    this.setState({
      [e.target.name]: e.target.value
    });
  }

  render() {
    return (
      <div className="Form">
          <input
            type="text"
            name="name"
            onChange={e => {
              this.handleUpdate(e);
            }}
          />
      </div>
    );
  }
}

class GeneralForm extends Component {
    constructor(props) {
        super(props);
    }

    render() {
        return <form className="GeneralForm">{this.props.children}</form>;
    }
}

class App extends Component {
    render() {
        return (
            <GeneralForm>
                <Form />
            </GeneralForm>
        );
    }
}

第一个问题:是否有一种优雅而有效的方法将逻辑从子组件(Form)发送到包装器组件(GeneralForm),例如handleUpdate函数?

组成作品的另一种方法是使用高阶组件。我们创建一个函数,该函数返回具有某些逻辑的组件。然后,我们将一个组件传递给此函数,结果将是具有该函数设置的逻辑的组件。这样,我们可以创建共享逻辑的组件。

const CustomFormHoc = WrappedComponent => {
  return class CustomForm extends Component {
    constructor(props) {
      super(props);
      this.state = {};
      this.handleUpdate = this.handleUpdate.bind(this);
      this.submitForm = this.submitForm.bind(this);
    }

    submitForm(e) {
      e.preventDefault();
      alert(JSON.stringify(this.state, null, 2));
    }

    handleUpdate(e) {
      this.setState({
        [e.target.name]: e.target.value
      });
    }

    render() {
      return (
        <WrappedComponent
          {...this.props}
          handleUpdate={this.handleUpdate}
          submitForm={this.submitForm}
        />
      );
    }
  };
};

class Form extends Component {
  render() {
    return (
      <div className="Form">
        <div>Form</div>
        <div className="Form">
          <input
            type="text"
            name="Address"
            placeholder="Address"
            onChange={e => {
              this.props.handleUpdate(e);
            }}
          />
          <input
            type="text"
            name="Postal code"
            placeholder="Postal code"
            onChange={e => {
              this.props.handleUpdate(e);
            }}
          />
          <input
            type="submit"
            onClick={e => {
              this.props.submitForm(e);
            }}
          />
        </div>
      </div>
    );
  }
}

let ComposedForm = CustomFormHoc(Form);

    class App extends Component {
  render() {
    return (
      <div>
        <ComposedForm />
      </div>
    );
  }
}

这可行,但是这是我的第二个问题:是否有一种方法可以避免将handleUpdate和SubmitForm传递给WrappedComponent?在Higher-Order Components示例中,它们被忽略了。

<WrappedComponent
    {...this.props}
    handleUpdate={this.handleUpdate}
    submitForm={this.submitForm}
/>

最后一个问题:这两种制作构图的方式中哪种更好,在哪种情况下?

谢谢!

0 个答案:

没有答案