reduxjs / redux-toolkit

The official, opinionated, batteries-included toolset for efficient Redux development
https://redux-toolkit.js.org
MIT License
10.69k stars 1.16k forks source link

[RTK Query]: Problems with rerenders with useMemo createSelector #4002

Open KnutHelstad opened 9 months ago

KnutHelstad commented 9 months ago

Hello and thank you for a brilliant library. I'm using @reduxjs/toolkit 1.9.7 I'm struggling with two custom hooks with a useMemo createSelector. Both retrieve data from the same query. One only retrieves an object (which works) and the other retrieves an array (which doesn't work)

This is the hook that works

const useGetSingelTagOPC = (tagname) => {

    const selectdb = useMemo(() => {
        const emptyObjekt = {};
        return createSelector(
            (res) => res.data,
            (res, name) => name,
            (data, name) => {
                const filteredData = data?.filter((tag) => tag.name === name) ?? emptyObjekt;
                return filteredData[0];
            }
        );
    }, []);

    const { opctag } = useGetTagsQuery(undefined, {
        selectFromResult: (result) => {
            // console.log(result);
            return {
                opctag: selectdb(result, tagname)
            };
        }
    });

    return { opctag };
};

export default useGetSingelTagOPC;

This is a hook that does not work and rerenders my component every time there is an update in useGetTagsQuery


const useGetTagGroupOPC = (dbmame) => {
    const selectTagsIndb = useMemo(() => {
        const emptyArray = [];
        return createSelector(
            (res) => res.data,
            (res, db) => db,
            (data, db) => {
                const filteredData = data?.filter((tag) => tag.db === db) ?? emptyArray;
                return filteredData;
            }
        );
    }, []);

    const { opctags } = useGetTagsQuery(undefined, {
        selectFromResult: (result) => {
            return {
                opctags: selectTagsIndb(result, dbmame)
            };
        }
    });

    return { opctags };
};

export default useGetTagGroupOPC;

Example of data from useGetTagsQuery

const exsampleArray = [
    {
        id: 63,
        name: 'FrontJobAGV2_DB_statusmaster_AGV_ACKtoOM',
        db: 'FrontJobAGV2_DB',
        value: false,
        type: 1
    },
    {
        id: 64,
        name: 'FrontJobAGV2_DB_statusmaster_DelivPosOK',
        db: 'FrontJobAGV2_DB',
        value: true,
        type: 1
    },
    {
        id: 65,
        name: 'FrontJobAGV2_DB_statusmaster_DelivPosNOK',
        db: 'FrontJobAGV2_DB',
        value: false,
        type: 1
    }
];

Need help here to understand what is wrong with useGetTagGroupOPC

In advance, thank you

KnutHelstad commented 8 months ago

After testing and perusing the documentation, I ended up with this code that worked as I wanted. Not sure if this is quite the right way.

import React, { useMemo } from 'react';
import { shallowEqual } from 'react-redux';
import { createSelector, lruMemoize, weakMapMemoize } from 'reselect';
import { useGetTagsQuery } from 'store/slices/lockalOPCUAAPI';

const useGetTagGroupOPC = (dbmame) => {
    const selectTagsIndb = useMemo(() => {
        const emptyArray = [];
        return createSelector(
            (result) => {
                // console.log('result', result);
                return result.data;
            },
            (_, db) => db,
            (data, db) => data?.filter((tag) => tag.db === db) ?? [],
            {
                memoize: lruMemoize,
                memoizeOptions: {
                  equalityCheck: shallowEqual,
                  resultEqualityCheck: shallowEqual,
                  maxSize: 3
                },
                argsMemoize: lruMemoize,
                argsMemoizeOptions: {
                  equalityCheck: shallowEqual,
                  resultEqualityCheck: shallowEqual,
                  maxSize: 3
                }
              }
            // (data, db) => exsampleArray ?? emptyArray
        );
    }, []);

    const { opctags } = useGetTagsQuery(undefined, {
        selectFromResult: (result) => {
            return {
                // ...result,
                opctags: selectTagsIndb(result, dbmame)
            };
        }
    });

    return { opctags };
};

export default useGetTagGroupOPC;