2

There is application which uses react, redux, react-redux, redux-thunk.

react:       "16.0.0-alpha.6"
redux:       "3.6.0"
react-redux: "5.0.2"
redux-thunk: "2.1.0"

Concept:

Reducers:

import { createStore, applyMiddleware } from 'redux';
import thunkMiddleware                  from 'redux-thunk';

export const MESSAGES_ADD_MESSAGE = 'MESSAGES_ADD_MESSAGE';
export const CONTACTS_ADD_CONTACT = 'CONTACTS_ADD_CONTACT';

export default function messages(state = { messages: [] }, action) {
    switch (action.type) {
        case MESSAGES_ADD_MESSAGE:
            return { messages: [ ...state.messages, action.message ] };
        default:
            return state;
    }
}

export default function contacts(state = { contacts: [] }, action) {
    switch (action.type) {
        case CONTACTS_ADD_CONTACT:
            return { contacts: [ ...state.contacts, action.contact ] };
        default:
            return state;
    }
}

const rootReducer = combineReducers({
    contacts,
    messages
});

Store:

const createStoreWithMiddleware = applyMiddleware(
    thunkMiddleware
)(createStore);

const store = createStoreWithMiddleware(rootReducer);

Actions creators:

export function addMessage(message) {
    return {
        type: MESSAGES_ADD_MESSAGE,
        message
    };
}

export function addContact(contact) {
    return {
        type: CONTACTS_ADD_CONTACT,
        contact
    };
}

Why time of dispatch(addContact('Viktor +123456789')) grows depending on count of messages in store?

As I understand in time of new store construct, the messages reducer returns state reference without creating new copy of this part of store.

I have more complicated real case but concept of issue is similar.

viktor_aky
  • 31
  • 5

1 Answers1

3

It does create a new copy whenever you mutate the state. If you want to improve the performance you should be using libraries like immutable.js, which offers many optimizations.

From the documentation -

As described in Reducers, a Redux reducer function:

Should have a signature of (previousState, action) => newState, similar to the type of function you would pass to Array.prototype.reduce(reducer, ?initialValue) Should be "pure", which means the reducer: Does not perform side effects (such as calling API's or modifying non-local objects or variables). Does not call non-pure functions (like Date.now or Math.random). Does not mutate its arguments. If the reducer updates state, it should not modify the existing state object in-place. Instead, it should generate a new object containing the necessary changes. The same approach should be used for any sub-objects within state that the reducer updates.

var makeArray = function ()
{
   var temp = [];
   for(let i= 0, i < 10000; i++)    
   temp.push(i);
   return temp;
}

var e = makeArray();
var f = makeArray();

function test1()
{ var x = e.push(8);
}


var t2 = performance.now();

test1();

var t3 = performance.now();


t3-t2  //0.02



function test2()
{ var y = [...f, 8]
}


var t2 = performance.now();

test2();

var t3 = performance.now();


t3-t2 //1.98

You can see test2 is slower than test1.

Akhil
  • 619
  • 1
  • 6
  • 14
  • Ok, but in this case, default case of switch operator in reducer for what? – viktor_aky Aug 02 '17 at 15:54
  • We are not mutating the state in default case, so it is safe to return the reference. – Akhil Aug 02 '17 at 15:56
  • Ok, if state of messages not mutating during "dispatch(addContact('Viktor +123456789'))", why time of this action grows depending on count of messages in store? – viktor_aky Aug 02 '17 at 16:02
  • During the dispatch a new state is being created, so it takes more time. See the example in my answer. – Akhil Aug 02 '17 at 17:00
  • Maybe I don't understand you. Or maybe you. I know that during the dispatch a new state is being created. But I think that the part (reducer) of store (state) which don't mutate should not recreated, only return reference and connecting by this reference to new state – viktor_aky Aug 02 '17 at 21:16