0

I'm trying to understand selectors in react with ReSelect, it's ok for now but i think something wrong with my logic.

1 - After ajax request, i get a list of "categories", with id, name and selected

2 - I'm using this list to create tags, when i click one of them, it change this parameter "selected" (true/false).

3 - Every "categories" are into a "product" which i can select with a dropdown.

Ok until now everything is working perfectly. onChange from my dropdown, i update my "product" states like that :

{fetching: false, items: [], selected: {}}
  • with the help of a selector, when the selected product change, i filter my categories to match my selection :

import {
    createSelector
} from 'reselect';

const getSelectedProduct = state => state.products.selected;
const getCategories = state => state.categories;

export const filterByProducts = () => {
    return createSelector(
        getSelectedProduct,
        getCategories,
        (mp, categories) => {

            if (mp && typeof mp === 'object') {
                const mpCategories = mp.categories.split(',');

                categories.items.map(item => {
                    item.selected = mpCategories.indexOf(item.id) >= 0;
                    return item;
                });
            }

            return categories;
        }
    )
}

When i change my product, it will update every selected categories, that's what i want. But onClick to a tag, i update categories states too :

export const selectCategory = category => {
    return (dispatch, getState) => {
        const state = getState();
        
        if (state.categories) {
            let categories = state.categories.items;

            categories.map(item => {
                if (item.id === category) {
                    item.selected = !item.selected;
                }
                return item;
            });

            dispatch(receiveCategories(categories));
        }
    }
}

The code is working, but because i changed states onClick, the selector will loop through every categories and make is matching again, but i would like to avoid that.

onChange product, selector will execute (good) onClick category, because of the new states made in my action.js, selector will run another time (not good).

I was thinking about to merge 2 selectors instead of making an action call, but i'm not sure about it...

If you have some advices, it would be great :)

Thank you !

jacman
  • 191
  • 9

1 Answers1

0

Ok, so i found something simple.

I created a new var called "selection" into my 'categories' actions to handle my selections (onclick tags).

Instead of watching state.categories, i only watch state.categories.items, so my "filterByProduct" will not update every time.

Then i created a new selector called 'updateSelectedCategories', which is watching 'filterByProduct' and state.categories.selection.

So, when i change my product, 'filterByProduct' and 'updateSelectedCategories' will update. When i change a category, only 'updateSelectedCategories' will update, so i don't love my previous matching.

Here the code :

import {
    createSelector
} from 'reselect';

const getSelectedProduct = state => state.products.selected;
const getCategories = state => state.categories.items;
const getSelection = state => state.categories.selection;

const filterByProduct = createSelector(
    getSelectedProduct,
    getCategories,
    (mp, categories) => {

        if (mp && typeof mp === 'object') {
            const mpCategories = mp.categories.split(',');

            categories.map(item => {
                item.selected = mpCategories.indexOf(item.id) >= 0;
                return item;
            });
        }

        return categories;
    }
);

export const updateSelectedCategories = createSelector(
    filterByProduct,
    getSelection,
    (categories, selection) => {

        if (selection.length > 0 && typeof selection === 'object') {
            categories.map(item => {
                if (selection.indexOf(item) >= 0) {
                    item.selected = true;
                }
                return item;
            });
        }

        return categories;
    }
);
jacman
  • 191
  • 9