简体   繁体   中英

Sharing data between two Redux Reducers/States

Is this a reasonable solution for data sharing between two states/reducers?

//combineReducers
function coreReducer(state = {}, action){

    let filtersState = filters(state.filters, action);
    let eventsState = events(state.events, action, { filters: filtersState});

    return { events: eventsState, filters : filtersState};

}

export const rootReducer = combineReducers(
    {
        core  : coreReducer,
        users
    }
);

If so, how can one guarantee the order in which reducer functions are executed if both answer to the same dispatched event and the second reducing function depends on the new state of the first one?

Let's say that we dispatch a SET_FILTER event that appends to activeFilters collection in the filters Store and later changes the visibility of items in the events Store with respect to the activeFilters values.

//ActiveFilters reducer
function filtersActions(state = {}, action){

    switch (action.type) {
        case SET_FILTER:
            return Object.assign({}, state, {
                [action.filterType]: action.filter
            })
        case REMOVE_FILTER:
            var temp = Object.assign({}, state);
            delete temp[action.filterType];
            return temp;

        case REMOVE_ALL_FILTERS:
            return {};

        default:
            return state
    }
}

I think I found the answer - Computing Derived Data - Reselect

http://redux.js.org/docs/recipes/ComputingDerivedData.html

/--------container--------/
import {getGroupsAndMembers} from '../reducers'
const mapStateToProps = (state) => {
  return {
    inputValue: state.router.location.pathname.substring(1),
    initialState: getGroupsAndMembers(state) <-- this one
 }
}


/--------reducers--------/
export function getGroupsAndMembers(state){
   let { groups, members } = JSON.parse(state)
   response = {groups, members}
   return response;
}


GroupsContainer.propTypes = {
 //React Redux injection
 pushState: PropTypes.func.isRequired,
 // Injected by React Router
 children: PropTypes.node,
 initialState:PropTypes.object,
}

don't forget to follow the guidelines for 'connect'

export default connect(mapStateToProps,{ pushState })(GroupsContainer)

If you have two reducers, and one depend on a value from a first one, you just have to update them carefully, and the best solution will be just to use a special function, which will first set the filtering, and then query corresponding events. Also, keep in mind that if events fetching is asynchronous operation, you should also nest based on filtering type -- otherwise there is a chance of race condition, and you will have wrong events.

I have created a library redux-tiles to deal with verbosity of raw redux, so I will use it in this example:

import { createSyncTile, createTile } from 'redux-tiles';

const filtering = createSyncTile({
  type: ['ui', 'filtering'],
  fn: ({ params }) => params.type,
});

const events = createTile({
  type: ['api', 'events'],
  fn: ({ api, params }) => api.get('/events', { type: params.type }),
  nesting: ({ type }) => [type],
});

// this function will just fetch events, but we will connect to apiEvents
// and filter by type
const fetchEvents = createTile({
  type: ['api', 'fetchEvents'],
  fn: ({ selectors, getState, dispatch, actions }) => {
    const type = selectors.ui.filtering(getState());
    return dispatch(actions.api.events({ type }));
  },
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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