javascript - ماهو - react ترجمة




استخدام mixins مقابل المكونات لإعادة استخدام التعليمات البرمجية في Facebook React (2)

لقد بدأت في استخدام Facebook React في مشروع Backbone وحتى الآن تسير الأمور على ما يرام.
ومع ذلك ، لاحظت أن بعض التكرار يزحف إلى شفرة React.

على سبيل المثال ، لدي العديد من عناصر واجهة المستخدم المشابهة INITIAL مع حالات مثل INITIAL و SENDING و SENT . عندما يتم الضغط على زر ، يحتاج النموذج إلى التحقق من صحته ، ويتم إجراء الطلب ، ثم يتم تحديث الحالة. يتم الاحتفاظ الدولة داخل this.state بالطبع ، جنبا إلى جنب مع قيم الحقل.

إذا كانت هذه مشاهدات أساسية ، فقد قمت باستخراج فئة أساسية تسمى FormView ولكن كان لدي انطباع أن React لا يؤيد ولا يدعم الفئة الفرعية لمشاركة منطق العرض (صححني إذا كنت مخطئًا).

لقد رأيت نهجين لإعادة استخدام الكود في React:

هل أقوم بتصحيح أن المزيج والحاويات مفضلة للوراثة في React؟ هل هذا قرار تصميم متعمد؟ هل من المنطقي استخدام مزيج أو مكون حاوية لمثال "النموذجية" الخاص بي من الفقرة الثانية؟

وهنا جوهر مع FeedbackWidget و JoinWidget في حالتها الراهنة . لديهم بنية مشابهة ، طريقة beginSend مشابهة beginSend كل منهما إلى بعض دعم التحقق من الصحة (ليس هناك حتى الآن).


تحديث: هذه الإجابة قديمة. ابتعد عن المزيج إذا استطعت. لقد حذرتك!
Mixins مات. يعيش تكوين طويل

في البداية ، حاولت استخدام مكونات فرعية لهذا واستخراج FormWidget و InputWidget . ومع ذلك ، تخليت عن هذا النهج في منتصف الطريق لأنني أردت تحسين التحكم في input المولدة input .

مقالتان ساعدتني كثيرًا:

اتضح أن أنا فقط بحاجة إلى كتابة FormMixin (مختلفة): ValidationMixin و FormMixin .
إليكم كيف فصلتهم.

ValidationMixin

يضيف mixing validation أساليب ملائمة لتشغيل وظائف المدقق الخاص بك على بعض خصائص الولاية الخاصة بك وتخزين خصائص "errored" في مصفوفة state.errors حتى تتمكن من تمييز الحقول المقابلة.

المصدر ( gist )

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 و resetError .
يتوقع من الفئة تعريف كائن propTypes ، على غرار propTypes :

var JoinWidget = React.createClass({
  mixins: [React.addons.LinkedStateMixin, ValidationMixin, FormMixin],

  validators: {
    email: Misc.isValidEmail,
    name: function (name) {
      return name.length > 0;
    }
  },

  // ...

});

عندما يضغط المستخدم على زر الإرسال ، أدعو إلى validate . ستجري مكالمة validate كل مدقق this.state.errors بتعبئة this.state.errors يحتوي على مفاتيح الخصائص التي فشلت في التحقق من الصحة.

في طريقة العرض الخاصة بي ، استخدم hasError لإنشاء فئة CSS الصحيحة للحقول. عندما يضع المستخدم التركيز داخل الحقل ، أدعو resetError لإزالة تمييز الخطأ حتى validate الاتصال التالي.

renderInput: function (key, options) {
  var classSet = {
    'Form-control': true,
    'Form-control--error': this.hasError(key)
  };

  return (
    <input key={key}
           type={options.type}
           placeholder={options.placeholder}
           className={React.addons.classSet(classSet)}
           valueLink={this.linkState(key)}
           onFocus={_.partial(this.resetError, key)} />
  );
}

FormMixin

شكل mixin يعالج شكل الحالة (للتحرير ، تقديم ، تقديم). يمكنك استخدامه لتعطيل المدخلات والأزرار أثناء إرسال الطلب ، وتحديث طريقة العرض الخاصة بك بالمقابل عند إرسالها.

المصدر ( gist )

define(function () {

  'use strict';

  var _ = require('underscore');

  var EDITABLE_STATE = 'editable',
      SUBMITTING_STATE = 'submitting',
      SUBMITTED_STATE = 'submitted';

  var FormMixin = {
    getInitialState: function () {
      return {
        formState: EDITABLE_STATE
      };
    },

    componentDidMount: function () {
      if (!_.isFunction(this.sendRequest)) {
        throw new Error('To use FormMixin, you must implement sendRequest.');
      }
    },

    getFormState: function () {
      return this.state.formState;
    },

    setFormState: function (formState) {
      this.setState({
        formState: formState
      });
    },

    getFormError: function () {
      return this.state.formError;
    },

    setFormError: function (formError) {
      this.setState({
        formError: formError
      });
    },

    isFormEditable: function () {
      return this.getFormState() === EDITABLE_STATE;
    },

    isFormSubmitting: function () {
      return this.getFormState() === SUBMITTING_STATE;
    },

    isFormSubmitted: function () {
      return this.getFormState() === SUBMITTED_STATE;
    },

    submitForm: function () {
      if (!this.isFormEditable()) {
        throw new Error('Form can only be submitted when in editable state.');
      }

      this.setFormState(SUBMITTING_STATE);
      this.setFormError(undefined);

      this.sendRequest()
        .bind(this)
        .then(function () {
          this.setFormState(SUBMITTED_STATE);
        })
        .catch(function (err) {
          this.setFormState(EDITABLE_STATE);
          this.setFormError(err);
        })
        .done();
    }
  };

  return FormMixin;

});

استعمال

من المتوقع أن يوفر المكون طريقة واحدة: sendRequest ، والتي يجب أن تعيد الوعد Bluebird. (إنه أمر بسيط تعديله للعمل مع Q أو مكتبة الوعد الأخرى.)

ويوفر أساليب الراحة مثل isFormEditable و isFormSubmitting و isFormSubmitted . كما يوفر طريقة لبدء الطلب: submitForm . يمكنك الاتصال به من خلال أزرار "معالج onClick ".


أنا أقوم ببناء سبا مع React (في الإنتاج منذ 1 سنة) ، وأنا تقريبا أبدا استخدام mixins.

و usecase الوحيد الذي لدي حاليا لخلطات هو عندما تريد مشاركة السلوك الذي يستخدم أساليب دورة حياة React ( componentDidMount الخ). تم حل هذه المشكلة بواسطة مكونات الترتيب الأعلى التي يتحدث بها Dan Abramov في ارتباطه (أو باستخدام ES6 class inheritance).

يتم استخدام المزيج في كثير من الأحيان في أطر العمل ، لجعل واجهة التطبيق API متاحة لجميع المكونات ، وذلك باستخدام ميزة السياق "المخفي" في React. هذا لن تكون هناك حاجة بعد الآن إما مع الميراث الطبقة 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 كود LinkedStateMixin بحيث يكون بناء الجملة:

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

هل هناك فرق كبير؟







reactjs