繁体   English   中英

如何使用Redux流程中的Async数据重新使用react组件?

[英]How to make a react component with Async data re-usable in Redux flow?

它更像是一个建筑问题而不是技术问题。 我正在开发具有以下结构的应用程序(Standard Redux)。

UserFormContainer-> UserForm - >(Fields,RoleField,Group Field)。 现在我的所有字段都是哑组件,但角色和组除外,它们依赖于要填充的服务器的数据。 根据标准redux,我的状态有单向流,所有数据都通过主容器,哑组件只调度动作。

我的问题是,由于角色和组字段依赖于它的数据的父组件,我如何使这些可重用? 什么是最佳做法?

这是我的基本组件的单向流程。

在此输入图像描述

RoleField应该是一个愚蠢的组件,它从UserForm组件获取数据。 UserForm应该从商店获取数据并将其作为props传递给RoleField 这样, RoleField将是可重用的,因为它们可以显示从父组件传递给它们的数据。

UDPATE

您还可以将UserForm为包装容器,该容器可以接受自定义表单字段作为子项。 请参阅下面的示例代码

render() {
  <UserForm>
    <RoleField customData={ dataFromStore }/>
  </UserForm>
}

@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;
}

并以还原形式重新使用组件我做了

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;

这是修改后的图表。 我不确定这是最佳做法还是有任何与之相关的缺点,但它只适用于我的用例。

州图:

组件状态图

对图表的道歉并不那么清楚。

可重复使用的Redux React组件

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM