Композиция и наследование: разделение логики между компонентами в React - PullRequest
0 голосов
/ 10 сентября 2018

У меня есть вопрос о наследовании и композиции в React.

Я привык к Backbone, где обычной процедурой является создание представлений классов, которые обрабатывают логику для данных и рендеринга. Когда у вас есть некоторые компоненты, которые разделяют часть этой логики - например, формы - вы можете абстрагировать ее, создав новый компонент (класс), добавить туда разделяемую логику, а затем расширить этот класс из других компонентов. Таким образом, можно получить абстрактный компонент с этой общей логикой и расширяющими ее компонентами:

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


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

Теперь я вижу, что React работает с композицией, а не наследованием. И есть два способа сделать композицию: обернуть компоненты или использовать Компоненты высшего порядка . Чтобы упростить задачу, я сделал Песочницу с этими двумя возможностями: 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 function?

Другой способ создания композиции - с использованием компонентов высшего порядка. Мы создаем функцию, которая возвращает компонент с некоторой логикой. Затем мы передаем компонент этой функции, и результатом будет компонент с логикой, установленной функцией. Таким образом, мы можем создавать компоненты, которые разделяют логику.

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? В примере высшего порядка они опущены.

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

И последний вопрос: какой из этих двух способов создания композиции лучше и для каких случаев?

Спасибо!

...