Reduxフローで非同期データを使用してreactコンポーネントを再利用できるようにするにはどうすればよいですか?

Aftab Naveed

これは、技術的な問題というよりも、アーキテクチャ上の問題です。私は次の構造(標準Redux)のアプリケーションに取り組んでいます。

UserFormContainer-> UserForm->(Fields、RoleField、GroupField)。これで、ロールとグループを除いて、すべてのフィールドがダムコンポーネントになりました。これらは、入力するサーバーからのデータに依存しています。標準のreduxによると、私の状態には一方向のフローがあり、すべてのデータはメインコンテナーを通過し、ダムコンポーネントはアクションのみをディスパッチします。

私の質問は、役割とグループのフィールドはデータの親コンポーネントに依存しているので、これらを再利用可能にするにはどうすればよいですか?ベストプラクティスは何ですか?

これが私の基本的なコンポーネントの一方向の流れです。

ここに画像の説明を入力してください

Aftab Naveed

@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}/>
                            &nbsp;{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;

これが改訂された図です。これがベストプラクティスなのか、それに関連する欠点があるのか​​はわかりませんが、私のユースケースではうまくいきました。

状態チャート:

コンポーネント状態チャート

図があまり明確でないことをお詫びします。

再利用可能なReduxReactコンポーネント

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

Related 関連記事

ホットタグ

アーカイブ