Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Design Redux actions and reducers for a React reusable component

I'm developing a large application with Redux and React and I decided to make some reusable components like custom checkboxes and radio buttons.

As I want to store this information into the Redux store to be able to debug state of the application easily and the same component have the same functionality everywhere, it seems a good idea to create reducers and actions for each component.

However Redux reducers return a new state and save it in the store with the name of the reducer as a key and this forbids having more than one component of the same type in the same page using the same actions and reducers but keeping different states.

I think there are two solutions to this problem:

  • Create different actions and reducers for each component that I use, even thought the component and it's functionalities are the same. This solutions doesn't seem a good solution because there will be a lot of redundant code.

  • Create actions with sufficient parameters to be able to differentiate each one in the reducer and that way change only the part of the state that is specified.

I went forward with the second option.

Actions file for the CheckBox component:

import {createAction} from 'redux-actions';

/****** Actions ******/
export const CHANGE_CHECKBOX_STATE = "CHANGE_CHECKBOX_STATE";

/****** Action creators ******/
export const changeCheckboxState = createAction(CHANGE_CHECKBOX_STATE, (block, name, state) => {
  return {
    block,
    name,
    state: {
      checked: state,
    }
  };
});

Reducers file for the CheckBox component:

import {handleActions} from 'redux-actions';

import {CHANGE_CHECKBOX_STATE} from './CheckBox.actions';

export const checkBoxComponent = handleActions({
  CHANGE_CHECKBOX_STATE: (state, action) => ({
    [action.payload.block]: {
      [action.payload.name]: action.payload.state
    }
  })
}, {});

I use block to specify the page, name to specify the name of the specific component (e.g. gender) and state as and object with the new state.

But this solution has some problems too:

  • Can't specify initial state of each component because the keys of the state are dynamic.
  • Complicates to much the store structure with a lot of nested states.
  • Aggregates data by component and not by form which will complicate debugging and it's logically incorrect.

I don't have enough experience with Redux and React to think of a better solution to this problem. But it seems to me that I'm missing something important about React-Redux relationship and this raises some questions:

  • Is it a good idea to store state of this reusable components into the Redux store?

  • Am I wrong in binding together React components with Redux actions and reducers?

like image 414
Roc Avatar asked Aug 28 '15 14:08

Roc


2 Answers

Don't describe your Redux reducers (your overall application state) in terms of the components that consume that state. Track it the other way, describing your application state in a descriptive manner and then have your "dumb" components consume that descriptive state.

Rather than tracking "The state of this checkbox for the form related to foo", track "this boolean value of foo" and then have the checkbox consume that state.

An example store for the checkbox:

const initialState = {
    someFooItem: { isCertainType: false }
};

export function foos(state = initialState, action) {
    switch(action.type){
        case(UPDATE_FOO_VALUE):
            return {
                ...state, 
                [action.payload.id]: {
                    isCertainType: action.payload.isCertainType
                }
            }
    }
}

An example checkbox consuming the store

class CheckBox extends React.Component {
    render() {
        return <input type="checkbox" checked={this.props.checked} />
    }
}

The parent component

class ParentComponent extends React.Component {
     render() {
         return <CheckBox checked={this.foo.isCertainType} />
     }
}
like image 95
travisbloom Avatar answered Nov 11 '22 04:11

travisbloom


The fundamental mistake here is that you have 0 dumb components. Basic controls like checkboxes should be dumb components using just props, their parent having the responsibility to select and update the proper piece of state for a particular checkbox.

like image 4
AlexG Avatar answered Nov 11 '22 04:11

AlexG