Facebook React에서 코드 재사용을 위해 믹스 인과 컴포넌트 사용
Backbone 프로젝트에서 Facebook React를 사용하기 시작했으며 지금까지는 정말 잘되고 있습니다.
그러나 일부 복제가 내 React 코드에 들어갑니다.
예를 들어, 나는 몇 가지 형태와 같은 위젯이 같은 상태로를 INITIAL
, SENDING
하고 SENT
. 버튼을 누르면 양식을 확인하고 요청한 다음 상태를 업데이트해야합니다. this.state
필드 값과 함께 상태는 물론 React 안에 유지 됩니다.
이것들이 백본 뷰라면, 나는 기본 클래스를 추출했을 것입니다. FormView
그러나 React는 뷰 로직을 공유하기 위해 서브 클래스를 승인하거나 지원하지 않습니다 (잘못되면 수정하십시오).
React에서 코드 재사용에 대한 두 가지 접근 방식을 보았습니다.
- 믹스 인 ( React와 함께 제공되는 LinkedStateMixin 과 같은 );
- 컨테이너 구성 요소 (예 : react-infinite-scroll ).
믹스 인과 컨테이너가 React에서 상속보다 선호되는 것이 맞습니까? 의도적 인 디자인 결정입니까? 두 번째 단락의“양식 위젯”예제에 믹스 인 또는 컨테이너 구성 요소를 사용하는 것이 더 합리적입니까?
여기에 현재 상태 FeedbackWidget
와 요점이JoinWidget
있습니다. 그것들은 비슷한 구조, 유사한 beginSend
방법을 가지고 있으며, 둘 다 약간의 검증 지원이 필요합니다 (아직없는).
업데이트 :이 답변은 구식입니다. 가능하면 믹스 인을 피하십시오. 경고 했어!
믹스 인은 죽었다. 장수 구성
처음에 나는이 및 추출을위한 하위 구성 요소를 사용하려고 FormWidget
하고 InputWidget
. 그러나 생성 된 input
s 및 해당 상태를 보다 잘 제어하기를 원했기 때문에이 접근법을 반쯤 포기했습니다 .
가장 도움이되는 두 가지 기사 :
- React에서 생각 하면 실제로 중첩 된 구성 요소를 원하지 않는다는 것을 알았습니다.
- 재사용 가능한 컴포넌트 에는 깔끔한 믹스 인 예제가 있습니다.
내가 두 (다른)이나 mixin을 쓸 필요가 있다고 밝혀졌다 : ValidationMixin
와 FormMixin
.
내가 그들을 분리하는 방법은 다음과 같습니다.
유효성 검사
Validation mixin은 편리한 상태 메소드를 추가하여 일부 주 속성에서 유효성 검사기 기능을 실행하고“오류가 발생한”속성을 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
있습니다.
클래스가 validators
객체 를 정의 할 것으로 예상 합니다 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
검사에 실패한 속성의 키가 포함 된 배열로 채워집니다 .
내 render
방법 에서는 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
양식 믹스 인은 양식 상태 (편집 가능, 제출, 제출)를 처리합니다. 요청이 전송되는 동안 입력 및 버튼을 비활성화하고 전송시 해당보기를 업데이트 할 수 있습니다.
소스 ( 장점 )
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;
});
용법
It expects component to provide one method: sendRequest
, which should return a Bluebird promise. (It's trivial to modify it to work with Q or other promise library.)
It provides convenience methods such as isFormEditable
, isFormSubmitting
and isFormSubmitted
. It also provides a method to kick off the request: submitForm
. You can call it from form buttons' onClick
handler.
I'm building an SPA with React (in production since 1 year), and I almost never use mixins.
The only usecase I currently have for mixins is when you want to share behavior that uses React's lifecycle methods (componentDidMount
etc). This problem is solved by the Higher-Order Components that Dan Abramov talk in his link (or by using ES6 class inheritance).
Mixins are also often used in frameworks, to make framework API available to all the components, by using the "hidden" context feature of React. This won't be needed anymore either with ES6 class inheritance.
Most of the other times, mixins are used, but are not really needed and could be easiler replaced with simple helpers.
For example:
var WithLink = React.createClass({
mixins: [React.addons.LinkedStateMixin],
getInitialState: function() {
return {message: 'Hello!'};
},
render: function() {
return <input type="text" valueLink={this.linkState('message')} />;
}
});
You can very easily refactor LinkedStateMixin
code so that the syntax would be:
var WithLink = React.createClass({
getInitialState: function() {
return {message: 'Hello!'};
},
render: function() {
return <input type="text" valueLink={LinkState(this,'message')} />;
}
});
Is there any big difference?
'Programing' 카테고리의 다른 글
제품 번들 크기를 줄이는 방법은 무엇입니까? (0) | 2020.07.22 |
---|---|
Go에 제네릭이없는 이유는 무엇입니까? (0) | 2020.07.22 |
무엇을합니까. (0) | 2020.07.22 |
특성으로 Java 8 기본 메소드 : 안전? (0) | 2020.07.22 |
.NET : 필요한 구성 설정이 누락되면 어떤 예외가 발생합니까? (0) | 2020.07.22 |