これは、技術的な問題というよりも、アーキテクチャ上の問題です。私は次の構造(標準Redux)のアプリケーションに取り組んでいます。
UserFormContainer-> UserForm->(Fields、RoleField、GroupField)。これで、ロールとグループを除いて、すべてのフィールドがダムコンポーネントになりました。これらは、入力するサーバーからのデータに依存しています。標準のreduxによると、私の状態には一方向のフローがあり、すべてのデータはメインコンテナーを通過し、ダムコンポーネントはアクションのみをディスパッチします。
私の質問は、役割とグループのフィールドはデータの親コンポーネントに依存しているので、これらを再利用可能にするにはどうすればよいですか?ベストプラクティスは何ですか?
これが私の基本的なコンポーネントの一方向の流れです。
@DeividasKaržinauskasの答えは、ネストされたコンポーネントがいくつかある場合に完全に理にかなっています。これは、そのようなシナリオに進むための合理的な方法だと思いますが、コンポーネントを他のコンポーネントから完全に独立させたいので、テスト可能で、何も含まれていません。データロジック私は少し異なるアプローチを思いついた。もちろん、DeividasKaržinauskasの回答が役に立ちました。
コンポーネントを完全に独立させるために、さらに別のコンテナーを作成しました。すべての副作用はアクション/アクションクリエーターによって処理され、データが独自の独立したレデューサーによって計算されている間もテスト可能です。次に、reduxを使用して状態を小道具として渡しました。
コードサンプル
import React from 'react';
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';
class RolesField extends React.Component {
componentWillMount() {
//if not fetched then fetch
this.props.fetchRoles();
}
roles() {
let {roles} = this.props;
if (roles.length > 0) {
const {input, label, placeholder, type, meta: {touched, error, warning}} = this.props;
let rolesUi = roles.map((role, index) => {
return (
<div className="checkbox" key={index}>
<label htmlFor={input.name}>
<input {...input} placeholder={placeholder} type={type}/>
{role.name} <a href="#">( Show Permissions )</a>
</label>
</div>
);
});
return rolesUi;
}
}
render() {
const {input, label, placeholder, type, meta: {touched, error, warning}} = this.props;
return (
<div className="form-group">
<label className="col-sm-2 control-label" htmlFor={input.name}>
Administrative Roles
</label>
<div className="col-sm-10">
{/*This section should be loaded from server,
the component should dispatch the event and role action should load the roles.*/}
{this.roles()}
</div>
</div>
);
}
}
//map state to props.
function mapStateToProps(state) {
return {
roles: state.roles.roles
}
}
function mapDispatchToProps(dispatch) {
let actionCreators = {
fetchRoles
};
return bindActionCreators(actionCreators, dispatch);
}
export default connect(mapStateToProps, mapDispatchToProps)(RolesField);
/*Action Types*/
const ROLE_FETCH_START = 'ROLE_FETCH_START';
const ROLE_FETCH_COMPLETE = 'ROLE_FETCH_COMPLETE';
/*End Action Types*/
/**
* Action Creator
* @returns {{type: string, payload: [*,*,*,*]}}
*/
function fetchRoles() {
const roles = [
{'id': 1, 'name': 'Super Admin'},
{'id': 2, 'name': 'Admin'},
{'id': 3, 'name': 'Manager'},
{'id': 4, 'name': 'Technical Lead'}
];
/*Action*/
return {
type: ROLE_FETCH_COMPLETE,
payload: roles
};
}
/**
* Roles Reducer
* @param state
* @param action
* @returns {*}
*/
export function rolesReducer(state = {roles: [], fetched: false}, action) {
switch (action.type) {
case ROLE_FETCH_COMPLETE :
return {
...state,
fetched: true,
roles: action.payload
};
break;
}
return state;
}
そして、コンポーネントをredux形式で再利用するために
import React from 'react';
import {Field, reduxForm} from 'redux-form';
import {renderInputField, renderDropdownList} from '../../page/components/field.jsx';
import RolesField from '../../page/containers/fields/roles.jsx';
import Box from '../../page/components/box.jsx';
import ActionButtons from '../../page/components/action-buttons';
class UserForm extends React.Component {
actionButtons() {
return [
{
'type' : 'submit',
'label' : 'Save',
'className' : 'btn-primary'
},
{
'type' : 'button',
'label' : 'Cancel',
'className' : 'btn-success',
'onClick' : this.props.reset
},
{
'type' : 'button',
'label' : 'Delete',
'className' : 'btn-danger'
}
]
}
render() {
const { handleSubmit } = this.props;
return (
<form className="form-horizontal" role="form" onSubmit={handleSubmit}>
<Box title="Add New User">
<ActionButtons buttons = {this.actionButtons()} />
<Field
name="roles[]"
component={RolesField}
label="Technical Lead"
type="checkbox"
className="form-control" />
</Box>
</form>
);
}
}
UserForm = reduxForm({
form: 'userForm',
validate
})(UserForm);
export default UserForm;
これが改訂された図です。これがベストプラクティスなのか、それに関連する欠点があるのかはわかりませんが、私のユースケースではうまくいきました。
状態チャート:
図があまり明確でないことをお詫びします。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加