How to put methods onto the objects in Redux state? How to put methods onto the objects in Redux state? reactjs reactjs

How to put methods onto the objects in Redux state?


In Redux, you don't really have custom models. Your state should be plain objects (or Immutable records). They are not expected to have any custom methods.

Instead of putting methods onto the models (e.g. TodoItem.rename) you are expected to write reducers that handle actions. That's the whole point of Redux.

// Manages single todo itemfunction todoItem(state, action) {  switch (action.type) {    case 'ADD':      return { name: action.name, complete: false };    case 'RENAME':      return { ...state, name: action.name };    case 'TOGGLE_COMPLETE':      return { ...state, complete: !state.complete };    default:      return state;  }}// Manages a list of todo itemsfunction todoItems(state = [], action) {  switch (action.type) {    case 'ADD':      return [...state, todoItem(undefined, action)];    case 'REMOVE':      return [        ...state.slice(0, action.index),        ...state.slice(action.index + 1)      ];    case 'RENAME':    case 'TOGGLE_COMPLETE':      return [        ...state.slice(0, action.index),        todoItem(state[action.index], action),        ...state.slice(action.index + 1)      ];  }}

If this still doesn't make sense please read through the Redux basics tutorial because you seem to have a wrong idea about how Redux applications are structured.


Dan's answer is of course correct in terms of how you should use redux when writing an application from scratch. My answer is based on a non-ideal motivating situation that may be similar to the OPs situation and how I am thinking of dealing with it.

I find myself trying create a redux application that depends on 3rd party libraries within the redux reducer that perform operations on input objects with methods, and I wanted to keep these input objects in the redux state. Here is my motivating situation in pseudo-code, and how I am "solving" it using lodash's assign method:

// Library A is a large 3rd party library I don't want to change// Library A expects instances of MyClass to have a method 'complexOperation', and also to have property 'a'LibraryA = class {  static reliesOnComplexOperation(myClassInstance) {    if (myClassInstance.complexOperation() && myClassInstance.a < 100) {      return true;    } else {      return false;    }  }}// MyClass is my own class that I control, and I want to store it's state and make changes to it using the redux reducer.MyClass = class {  constructor() {    this.a = 0;  }  myComplexOperation() {    return a > 10;  }}//and here is my redux reducer, making use of Library Afunction reducer(state, action) {  switch (action.type) {    case CHANGE_MY_CLASS:      const myClassInstancePlain = state.myClassInstance;      // redux has converted myClassInstance into a plain object with no methods, so we need to create a new instance of MyClass, and assign property values from the plain object to the new instance. Using the assign function from lodash library to achieve this - likely not the most efficient way      const myClassInstance = _.assign(new MyClass(), myClassInstancePlain);      // now I can pass myClassInstance off to LibraryA, and the complexOperation method will be available      if (LibraryA.reliesOnComplexOperation(myClassInstance)) {        myClassInstance.a = 50;      }      // I can return myClassInstance as part of the new state, and redux will convert it to a plain object      return {        ...state,        myClassInstance      };    default:      return state;  }}

So this example shows one way of incorporating objects with methods in the redux state as plain objects, and then adding back the methods so they can be used within the redux reducer. Would love to hear Dan's or anyone else's thoughts on this pattern or how it could be done better. I've seen Dan post in several places that storing objects with methods is a bad idea in redux, so the goal here is to find a way to store the object as a plain object and attach the methods when you need them in an efficient way.


I'm not sure this is exactly relevant (the context is using Redux with React), but I found this page while searching for something similar, so I'm writing this in case it is of interest.

My motivation is, I have have state objects where I would like to expose a representation of that state rather than the state itself. So for example (using Immutable.js), I have a state (a schema) that comprises one or more fields, each identified by a unique identifier and stored in a Map, plus a List of identifiers that gives the field ordering.

I really don't want to writing stuff like

state.get('field').get(state.get('order').get(nth))

to get the nth field anywhere other than close to the reducer, so that the internal representation is hidden and can be changed easily.

What I'm currently doing (and this is a bit of an experiment), is to add a function in the same file as the reducer:

schema.mapVisibleState = function (state) {    return {        getOrderedFields: () => state.get('order').map((fid) => state.get('fields').get(fid)    }}

This is used in the corresponding React components (along with a similarly motivated schema.bindActionCreators function):

export const Schema = connect(    (state) => schema.mapVisibleState (state),    (dispatch) => schema.bindActionCreators (dispatch))(_Schema) ;

Now I can access the fields, in the correct order, inside the component simply as this.props.getOrderedFields() and not worry about the underlying representation. It also has the additional nice property that it is easy to do dependency injection of the getOrderedFields() function.

Also, since I have a similar structure for the field state, I can extend this:

schema.mapVisibleState = function (state) {    return {        getOrderedFields: () => state.get('order').map((fid) => field.mapVisibleState(state.get('fields').get(fid)),        getNthField (nth) => field.mapVisibleState(state.get('fields').get(state.get('order').get(nth)))    }}