저는 Backbone 프로젝트에서 Facebook React를 사용하기 시작했으며 지금까지 정말 잘 진행되고 있습니다.
그러나 React 코드에 중복이 발생하는 것을 발견했습니다.
예를 들어, 나는 몇 가지 형태와 같은 위젯이 같은 상태로를 INITIAL
, SENDING
하고 SENT
. 버튼을 누르면 양식의 유효성을 검사하고 요청한 다음 상태를 업데이트해야합니다. 상태는 this.state
물론 필드 값과 함께 React 내부에 보관 됩니다.
이것이 Backbone 뷰라면,라는 기본 클래스를 추출했을 FormView
것이지만 React는 뷰 로직을 공유하기 위해 서브 클래 싱을 지원하지도 지원하지도 않는다는 인상을 받았습니다 .
React에서 코드 재사용에 대한 두 가지 접근 방식을 보았습니다.
- Mixins (예 : React와 함께 제공되는 LinkedStateMixin );
- 컨테이너 구성 요소 (예 : react-infinite-scroll ).
믹스 인과 컨테이너가 React의 상속보다 선호된다는 것이 맞습니까? 이것은 의도적 인 디자인 결정입니까? 두 번째 단락의 “양식 위젯”예제에 mixin 또는 컨테이너 구성 요소를 사용하는 것이 더 합리적입니까?
여기에 요지입니다 FeedbackWidget
및 JoinWidget
현재 상태는 . 그들은 유사한 구조, 유사한 beginSend
방법을 가지고 있으며 둘 다 일부 유효성 검사 지원이 필요합니다 (아직 존재하지 않음).
답변
업데이트 :이 답변은 구식입니다. 가능하면 믹스 인을 멀리하십시오. 경고 했어!
Mixins는 죽었습니다. 긴 라이브 작곡
처음에는이를 위해 하위 구성 요소를 사용 FormWidget
하고 InputWidget
. 그러나 생성 된 input
s와 그 상태에 대한 더 나은 제어를 원했기 때문에이 접근 방식을 중간에 포기했습니다 .
가장 도움이 된 두 가지 기사 :
- React를 생각하면서 실제로 중첩 된 컴포넌트를 원하지 않는다는 것을 깨달았습니다.
- 재사용 가능한 구성 요소 에는 깔끔한 믹스 인 예제가 있습니다.
내가 두 (다른)이나 mixin을 쓸 필요가 있다고 밝혀졌다 : ValidationMixin
와 FormMixin
.
내가 그들을 분리 한 방법은 다음과 같습니다.
유효성 검사
유효성 검사 믹스 인은 상태의 일부 속성에서 유효성 검사기 함수를 실행하고 “오류가 발생한”속성을 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;
});
용법
컴포넌트가 sendRequest
Bluebird promise를 반환해야하는 하나의 메서드를 제공 할 것으로 예상합니다 . (Q 또는 다른 promise 라이브러리와 함께 작동하도록 수정하는 것은 간단합니다.)
이 같은 편리한 방법을 제공합니다 isFormEditable
, isFormSubmitting
하고 isFormSubmitted
. 또한 요청을 시작하는 방법을 제공합니다 submitForm
.. 폼 버튼의 onClick
핸들러 에서 호출 할 수 있습니다 .
답변
React로 SPA를 구축하고 있으며 (1 년 이후 생산 중) 믹스 인을 거의 사용하지 않습니다.
현재 믹스 인에 대한 유일한 사용 사례는 React의 수명주기 메서드 ( componentDidMount
등) 를 사용하는 동작을 공유하려는 경우 입니다. 이 문제는 Dan Abramov가 자신의 링크 에서 말하는 Higher-Order Components (또는 ES6 클래스 상속 사용)로 해결됩니다.
Mixins는 React 의 “숨겨진” 컨텍스트 기능 을 사용하여 모든 구성 요소에서 프레임 워크 API를 사용할 수 있도록 프레임 워크에서 자주 사용됩니다 . 이것은 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')} />;
}
});
큰 차이가 있습니까?