Alicia
Alicia

Reputation: 29

Problem of optimization of a React-Redux-Reselect app

I have only been using React and Redux for some months, and I have implemented Reselect recently in order to try and make the application faster. I can't get it to work the way I would like it to, and I'm not sure where the problem comes from.

I resumed the development of a Planning app for the dev department I work for. The main page can have a certain number of weeks, contained in a Row. Each day of the week is a Component, and in each Day Component, you may have a TimePlanned Component. There is one Row Component line per ticket affected to a developer, and there can be as many as 10 tickets per user, so...there are a lot of Components.

I implemented Reselect so that my many connected Components did not get re-rendered as often as they used to be with Redux alone.

I have a problem with the Day Component. I am trying to have them access the smallest amount of data possible, to prevent the other Day from re-rendering when they are not concerned about the change.

Here is what the data that I want to 'sort' might look like :

planifie:{
   tickets : {
     29859 : {
       ticketId : 29859,
       typeId : 1,
       projectId : 6,
       userId : 3;
       planifications : [549],
       comments : []
     }
   },
   planifications : {
      549 : {
         planId : 549,
         ticketId : 29859,
         planDate : "2019-05-16",
         planTime : 480,
         userId : 3
      },
      550 : {
         planId : 550,
         ticketId : 29859,
         planDate : "2019-05-16",
         planTime : 480,
         userId : 6
      }
   },
   users : {
      3 : {
       userId : 3,
       userName : "pdupont",
       tickets : [29859],
       comments : [],
       planifications : [549]
      }
   }
}

There are, of course, several records for each 'category'.

My selectors looks like this :

export const getAllPlans = state => state.planifie.planifications
export const getGroup = state =>  _.find(state.filters.plannedFilters.groupBy, ['isActive', true])
export const getUserPropsId = (state,props) => props.userId

export const makeGetAllPlans = () => {
    return createSelector(
        getAllPlans,
        plans => plans
    )
}

export const makeGetRelevantObjectPlans = () => {
    return createSelector(
        [getAllPlans,getGroup,getUserPropsId],
        (planifications,group,user) => {
            switch (group.code) {
                case 'project':
                    return _.filter(planifications, {projectId : user})
                case 'user':
                    return _.filter(planifications, {userId : user})
                case 'type':
                    return _.filter(planifications, {typeId : user})
            }
        }
    )
}

The props.userId is always a number, but if my planifications are sorted by projets, it will be equivalent to a projectId. The memoized selector's goal is to return the planifications object relevant to the Id passed in props.

For this example, my filter is by user. I would like a Row of my Day components to only get access to the planifications with a '3' userId.

In my Day Component, this is how I call the selector :


const makeMapStateToProps = () => {
    const getComs = makeGetRelevantComments()
    const getPlans = makeGetRelevantPlans()
    const getPlanifications = makeGetRelevantObjectPlans()
    const mapStateToProps = (state, props) => {
        return {
            coms : getComs(state,props),
            plans : getPlans(state,props),
            planifications : getPlanifications(state,props)
        }
    }
    return mapStateToProps
}

const mapDispatchToProps = (dispatch) => (
    bindActionCreators(ActionsCreators, dispatch)
)

export default connect(makeMapStateToProps, mapDispatchToProps)(Day)

I put a function in my componentDidUpdate() to see what triggers re-renders, and on every Day Component, even the ones with a different props.userId, the planifications change, so my page takes very long to load.

For example, if I update the date of one planification with this Redux reducer action :

case types.SET_PLAN:
            return {
                ...state,
                planifie: {
                    ...state.planifie,
                    planifications : {
                        ...state.planifie.planifications,
                        [action.data.planId] : {

                 ...state.planifie.planifications[action.data.planId],
                            ...action.data.plan
                        }
                    }
                },
                isLoading: false
            }

Then every single one of my Day Component gets re-rendered.

I am wondering if I am missing something in my code, if I misunderstood what a memoized selectors can do, if the lodash filter function prevents is interfering with the immutability of the code, or if my data is not formated for this type of thing.

Thank you.

Upvotes: 0

Views: 279

Answers (1)

Max Shastsel
Max Shastsel

Reputation: 334

I ran through your code and there very few things that might be helpful:

1.getGroup selector must be memoized, because after each update of store _.find will return new Array and memoization for makeGetRelevantObjectPlans will be broken.

So getGroup might look like:

const groupBy = state => state.filters.plannedFilters.groupBy;

const getGroup = createSelector(
  [groupBy],
  (groupBy) => _.find(groupBy, ['isActive', true]),
);
  1. Using of createStructuredSelector instead of makeMapStateToProps might also be helpful

Upvotes: 1

Related Questions