'useSelector does not work when I set two state inside?

Why doesn't my code work? I am trying to separate these two things into one, but useSelector does not work.

This code works

  const st = useSelector((state) =>
     state.or.st
   );

   const ter = useSelector(
     ({ main }) => main.st.ter
  );

This code does not work

I want to put these two things in one useSelector and not in two?



Solution 1:[1]

Issue 1: Incorrect Function Usage

The useSelector hook expects a function that takes a single parameter state.

state is the whole state held by redux.

This would mean that your combine function should look more like the following:

const { units, organistationTerminology } = useSelector(state => {
    organistationTerminology = state.main.organisation.terminology;

    units = state.organisationStructure.units.sort(
        (a, b) => a.sortOrder - b.sortOrder
    );

    return {
        organistationTerminology, 
        units
    }
});

Issue 2: Changing Reference

The combined selector function returns a new object which will have a difference reference each time the selector function is computed.

The default comparison used by useSelector to detect a change between values is a reference comparison.

This will result in your component being rerendered on any store change regardless of whether state.main.organisation.terminology or state.organisationStructure.units is updated.

Issue 3: Computation in Selector

Selectors will run on each store change and the resulting value will be compared with the previous value to determine whether a component rerender needs to be triggered.

This means that even if state.organisationStructure.units never changes you will still be running a sort on every store change.

Computations should, where possible, be preformed outside of the selector function.

Issue 4: Sort on State Value

sort() sorts the array in place which would be mutating your state.

Conclusion

Selector functions should be kept as simple / quick as possible as they will be run on every store change.

Pulling multiple values from separate sections of state in one selector usually adds more complexity than it is worth.

My suggestion would be to keep it simple:

const units = useSelector(state => state.organisationStructure.units);

const organistationTerminology = useSelector(state => state.main.organisation.terminology);

const sortedUnits = [...units].sort();

// OR the sort can be memoized using units as a dependency;
const sortedUnits = useMemo(() => [...units].sort(), [units]);

If this is something you will be reusing in a number of components you could wrap it up in a custom hook:

const useTerminologyAndSortedUnits = () => {
    const units = useSelector(state => state.organisationStructure.units);

    const terminology = useSelector(state => state.main.organisation.terminology);

    const sortedUnits = useMemo(() => [...units].sort(), [units]);

    return {
        units: sortedUnits,
        terminology
    }
};

// The following can then be used in any of your function components
const { units, terminology } = useTerminologyAndSortedUnits()

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Jacob Smit