Redux - два контейнера могут совместно использовать состояние? - PullRequest
0 голосов
/ 05 октября 2018

Я новичок в React и Redux.Я нахожусь в точке, где я пытаюсь перенести несколько контейнеров в родительский контейнер, форму.

Я начал с создания компонента Select, который повторно используется с помощью Redux.

Компонент Select имеет один набор действий.Но существуют уникальные редукторы для каждого экземпляра компонента Select.Все собрались вместе, создав контейнер для каждого экземпляра Select.(См. Код ниже).

Контейнеры Select работают отлично.И сосуществуют на той же странице без проблем.

Так что теперь Я хочу "связать их" в форму . Форма должна знать, какое значение выбрал пользователь. Поэтому я подумал, что мог бы сделать это, сопоставив свойства формы с соответствующими битами состояния, связанными с контейнерами Select. Это работает для инициализации, но когда я выбираю элемент в одном из контейнеров выбора, новое значение не отражается в контейнере формы.

Можно ли это сделать?

/reducers/base_reducers/SingleSelect.js

import { FETCH_ITEMS, ADD_ITEM, SET_VALUE, SHOW_LOADING, SHOW_ERROR } from "../../constants";

// Defines STATE for the SingleSelect component and initial defaults. Any key with a value of 'DEFINE'
// must be INITIALIZED in the model reducer. Remaining items can also be modified or left as initialized here.
export const base_reducer_single_select_state = {
    namespace: 'DEFINE',
    componentId: 'DEFINE',
    items: ['DEFINE',],
    defaultValue: 'DEFINE',
    selectItem: '0',
    allowAdd: true,
    validationRegEx: /^[a-zA-Z ]*$/,
    regExDescription: 'letters and spaces.',
    errorMessage: '',
    isError: false,
    isLoading: false,
    apiRoute: 'DEFINE',
};

// Processes state changes from actions for the Simple Select component.
export function base_reducer_single_select(state, action) {
    switch (action.type) {
        case `${state.namespace}/${FETCH_ITEMS}`:
            action.items.unshift(state.defaultValue);
            return {...state, "items": action.items};
        case `${state.namespace}/${ADD_ITEM}`:
            return {...state, "selectItem": action.itemValue};
        case `${state.namespace}/${SET_VALUE}`:
            return {...state, "selectItem": action.newValue};
        case `${state.namespace}/${SHOW_ERROR}`:
            return {...state,
                "isError": action.trueFalse,
                "errorMessage": action.message};
        case `${state.namespace}/${SHOW_LOADING}`:
            return {...state, "isLoading": action.value};
        default:
            return state;
    }
}

И вот пара редукторов, которые реализуют универсальный редуктор SimpleSelect:

/reducers/City.js

import { base_reducer_single_select, base_reducer_single_select_state } from './base_reducers/SingleSelect';
import { getNamespace } from '../helpers';

const defaultValue = {id: 0, name: "- Select city -"};

const initialState = {
    ...base_reducer_single_select_state,
    namespace: getNamespace(),
    componentId: 'City',
    items: [
        defaultValue,
    ],
    defaultValue: defaultValue,
    apiRoute: '/api/cities/',
};

export default function city(state=initialState, action) {
    return base_reducer_single_select(state, action);
}

/reducers/State.js

import { base_reducer_single_select, base_reducer_single_select_state } from './base_reducers/SingleSelect';
import { getNamespace } from '../helpers';

const defaultValue = {id: 0, name: '- Select state -'};

const initialState = {
    ...base_reducer_single_select_state,
    namespace: getNamespace(),
    componentId: 'State',
    items: [
        defaultValue,
    ],
    defaultValue: defaultValue,
    apiRoute: '/api/states/',
};

export default function state_name(state=initialState, action) {
    return base_reducer_single_select(state, action);
}

Их контейнеры:

import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import SingleSelectComponent from '../components/SingleSelectComponent';
import * as CityActions from '../actions/SingleSelect';

const mapStateToProps = state => {
    return {
        namespace: state.city.namespace,
        componentId: state.city.componentId,
        items: state.city.items,
        selectItem: state.city.selectItem,
        allowAdd: state.city.allowAdd,
        validationRegEx: state.city.validationRegEx,
        regExDescription: state.city.regExDescription,
        errorMessage: state.city.errorMessage,
        isError: state.city.isError,
        isLoading: state.city.isLoading,
        apiRoute: state.city.apiRoute
    };
};

function mapDispatchToProps(dispatch) {
    return {actions: bindActionCreators(CityActions, dispatch)};
}

const CityContainer = connect(
    mapStateToProps,
    mapDispatchToProps
)(SingleSelectComponent);

export default CityContainer;

import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import SingleSelectComponent from '../components/SingleSelectComponent';
import * as StateActions from '../actions/SingleSelect';

const mapStateToProps = state => {
    return {
        namespace: state.state_name.namespace,
        componentId: state.state_name.componentId,
        items: state.state_name.items,
        selectItem: state.state_name.selectItem,
        allowAdd: state.state_name.allowAdd,
        validationRegEx: state.state_name.validationRegEx,
        regExDescription: state.state_name.regExDescription,
        errorMessage: state.state_name.errorMessage,
        isError: state.state_name.isError,
        isLoading: state.state_name.isLoading,
        apiRoute: state.state_name.apiRoute
    };
};

function mapDispatchToProps(dispatch) {
    return {actions: bindActionCreators(StateActions, dispatch)};
}

const StateNameContainer = connect(
    mapStateToProps,
    mapDispatchToProps
)(SingleSelectComponent);

export default StateNameContainer;

И контейнер "формы" (который еще не является формой, так как я только делаю первоначальное тестирование)

import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import CompanyInfoComponent from '../components/CompanyInfoComponent';
import * as CompanyInfoActions from '../actions/CompanyInfo';


const mapStateToProps = state => {
    return {
        namespace: state.company_info.namespace,
        componentId: state.company_info.componentId,
        childCityValue: state.city.selectItem,
        childStateValue: state.state_name.selectItem,
        childCountryValue: state.country.selectItem,
        validationRegEx: state.company_info.validationRegEx,
        regExDescription: state.company_info.regExDescription,
        errorMessage: state.company_info.errorMessage,
        isError: state.company_info.isError,
        isLoading: state.company_info.isLoading,
        apiRoute: state.company_info.apiRoute
    };
};

function mapDispatchToProps(dispatch) {
    return {actions: bindActionCreators(CompanyInfoActions, dispatch)};
}

const CompanyInfoContainer = connect(
    mapStateToProps,
    mapDispatchToProps
)(CompanyInfoComponent);

export default CompanyInfoContainer;

Опять же, начальные значения отображаются правильно.Но когда изменяется состояние, например, когда я выбираю город, состояние меняется, когда я проверяю состояние, связанное с городом (state.city.selectItem), но это не отражается в контейнере CompanyInfo.

Заранее благодарим за то, что уделили время на прочтение всего этого кода и любую информацию и помощь, которые вы можете предоставить.

...