Использование mixins vs components для повторного использования кода в Facebook React

Я начинаю использовать Facebook React в базовом проекте, и до сих пор все идет очень хорошо.
Тем не менее, я заметил некоторое дублирование, ползущее в мой код реакции.

например, у меня есть несколько виджетов, подобных форме С такими состояниями, как INITIAL, SENDING и SENT. При нажатии кнопки необходимо проверить форму, сделать запрос и обновить состояние. Состояние хранится внутри React this.state конечно, вместе с полем ценности.

если бы это были базовые представления, я бы извлек базовый класс под названием FormView но у меня сложилось впечатление, что React не одобряет и не поддерживает подклассы для обмена логикой просмотра (поправьте меня, если я ошибаюсь).

Я видел два подхода к повторному использованию кода в React:

Я прав, что миксины и контейнеры предпочтительнее наследования в React? Это преднамеренное дизайнерское решение? имеет ли смысл использовать mixin или компонент контейнера для моего примера "виджета формы" из второго абзаца?

вот суть с FeedbackWidget и JoinWidget в их нынешнем состоянии. У них похожая структура, похожие beginSend метод и оба будут нуждаться чтобы иметь некоторую поддержку проверки (еще нет).

2 ответов


Update: этот ответ устарел. Держись подальше от миксинов, если сможешь. Я тебя предупреждал!
Миксины Мертвы. Да Здравствует Композиция

сначала я попытался использовать подкомпоненты для этого и извлечь FormWidget и InputWidget. Однако я отказался от этого подхода на полпути, потому что хотел лучше контролировать сгенерированный inputS и их состояние.

две статьи, которые помогли мне большинство:

оказалось, что мне нужно было написать только два (разных) миксина:ValidationMixin и FormMixin.
Вот как я их разделил.

ValidationMixin

Validation mixin добавляет удобные методы для запуска валидатора функции на некоторых свойствах вашего государства и хранят свойства "error'D" в state.errors массив, чтобы вы могли выделить соответствующие поля.

источник (суть)

define(function () {

  'use strict';

  var _ = require('underscore');

  var ValidationMixin = {
    getInitialState: function () {
      return {
        errors: []
      };
    },

    componentWillMount: function () {
      this.assertValidatorsDefined();
    },

    assertValidatorsDefined: function () {
      if (!this.validators) {
        throw new Error('ValidatorMixin requires this.validators to be defined on the component.');
      }

      _.each(_.keys(this.validators), function (key) {
        var validator = this.validators[key];

        if (!_.has(this.state, key)) {
          throw new Error('Key "' + key + '" is defined in this.validators but not present in initial state.');
        }

        if (!_.isFunction(validator)) {
          throw new Error('Validator for key "' + key + '" is not a function.');
        }
      }, this);
    },

    hasError: function (key) {
      return _.contains(this.state.errors, key);
    },

    resetError: function (key) {
      this.setState({
        'errors': _.without(this.state.errors, key)
      });
    },

    validate: function () {
      var errors = _.filter(_.keys(this.validators), function (key) {
        var validator = this.validators[key],
            value = this.state[key];

        return !validator(value);
      }, this);

      this.setState({
        'errors': errors
      });

      return _.isEmpty(errors);
    }
  };

  return ValidationMixin;

});

использование

ValidationMixin есть три способа: validate, hasError и resetError.
Он ожидает, что класс определит


Я строю СПА с React (в производстве с 1 года), и я почти никогда не использую миксины.

единственный usecase у меня в настоящее время для mixins, когда вы хотите поделиться поведением, которое использует методы жизненного цикла React (componentDidMount и т. д.). Эта проблема решается компонентами высшего порядка, о которых говорит Дан Абрамов в своем ссылке (или с помощью наследования класса ES6).

Mixins также часто используются в рамках, чтобы сделать framework API доступным для всех компоненты, используя "hidden"контекстный элемент реагирует. Это больше не понадобится с наследованием класса ES6.


В большинстве других случаев используются миксины, но на самом деле они не нужны и могут быть заменены простыми помощниками.

например:

var WithLink = React.createClass({
  mixins: [React.addons.LinkedStateMixin],
  getInitialState: function() {
    return {message: 'Hello!'};
  },
  render: function() {
    return <input type="text" valueLink={this.linkState('message')} />;
  }
});

вы можете очень легко рефакторинг LinkedStateMixin код, чтобы синтаксис был:

var WithLink = React.createClass({
  getInitialState: function() {
    return {message: 'Hello!'};
  },
  render: function() {
    return <input type="text" valueLink={LinkState(this,'message')} />;
  }
});

есть ли большая разница?