Search code examples
reactjsreduxreact-redux

How to connect Reused Reducers Logic into React components?


I'm using the pattern described here that show us how to reuse reducer logic for other similar purposes.

So, my reducer code is like the code below:

function ContentFilterReducer(entity = ''){
    initialState.groupFilter = entity;
    return function ContentFilterReducer(state = initialState, action)
    {

        // is the entity that we want to update?
        if (action.item !== undefined && action.item.groupFilter !== entity)
            return state;

        switch (action.type) {
            case ContentFilterTypes.ADD_ITEM:
                return {
                    // we set the 
                    groupFilter: action.item.groupFilter,
                    listObjects : state.listObjects.push(new Map({
                        id: action.item.id,
                        description: action.item.description,
                        imgSrc: action.item.imgSrc
                    }))
                } 
        
            default:
                return state;
        }
    }
}

My combinedReducer describe a reducer for each purpose, as we can see below:

const SearchReducers = combineReducers({
    // contains all allowed filters to be selected
    UsersContentFilterReducer : ContentFilterReducer(Types.users),
    OrganizationsContentFilterReducer : ContentFilterReducer(Types.organizations)

})

Everything is working great, however I'd like to know, how to connect it in a React component using the connect function from React-Redux?

As we can see, I can define the reducer setting an entity (a simple char like 'a', 'o', etc.) and, to call the specific reducer, I need only set the entity in my action. And now, the problem is how to connect a specific reducer for a specific presentational component?

The code below is my HOC container that connect the reducer to a specific component, however, the code is the old version, without defining which reducer should call.

const mapStateToProps = (state, action) => {
    return {
        contentList: ContentFilterReducer(state.ContentFilterReducer, action)
    }
}

/**
 * 
 * @param {contains the action that will be dispatched} dispatch 
 */
const mapDispatchToProps = (dispatch) => {
    return {
        onAddClick: (groupFilter, filterDescription, operator, value) => {
            dispatch(AddFilter(groupFilter, filterDescription, operator, value));
        }
    }
}

export default connect(mapStateToProps, mapDispatchToProps)(ContentFilterField)

Solution

  • You don't connect a reducer. You connect a component to the Redux store. I won't name my state xxxReducer, it's a little bit confusing.

    I'm not sure what your app looks like, for a simple case, you just need to: (connect both state)

    const mapStateToProps = (state) => {
      return {
        userContentList: state.SearchReducers.UsersContentFilterReducer,
        organizationContentList: state.SearchReducers.OrganizationsContentFilterReducer,
      }
    }
    

    If you want to switch between usersContent and organizationsContent dynamically based on your component's state, what you need is a selector function.

    This is the official redux example: https://github.com/reactjs/redux/blob/master/examples/shopping-cart/src/reducers/index.js#L10-L26

    These functions are selectors, you import and use them to get the state you want.

    So you will create something like getContentList and it accepts a type like Types.users

    const mapStateToProps = (state) => {
      return {
        // suppose you save current type saved in SearchReducers.type
        contentList: getContentList(state.SearchReducers.type)
      }
    }
    

    Also, the second parameter of mapStateToProps is ownProps not action.