What is the alternative to using selectors with props in ngrx - ngrx

I am reading about selectors on the ngrx website and I stumbled upon selectors with props.
The ngrx team said it is deprecated but they didn't provide alternative to it. I want to use selectors with props in my application.
Is there any other alternative to using selectors with props?
If there is, how do I do it?.

The word "deprecated" in the notice is actually a link, though a hard one to notice due to the color of the banner it's in. It links to a GitHub Issue discussing selectors with props.
That issue raises the concern that, with Angular 12+ being in strict mode by default, developers are likely to run into a shortcoming in the implementation of selectors with props - namely that the prop values are not strongly typed or may be incorrectly typed.
The suggested approach is to use a factory selector. Essentially, instead of passing props as parameters of the selector, you take the props as arguments to a function defined by the selector.
So instead of:
export const getCount = createSelector(
getCounterValue,
(counter, props) => counter * props.multiply
);
const count = this.store.select(getCount, 5);
You would use:
export const getCount = (multiply: number) => createSelector(
getCounterValue,
(counter) => counter * multiply
);
const count = this.store.select(getCount(5));
Gunnar B.'s comment helpfully links to a migration guide with a section about moving from selectors with props to factory selectors if you need more information.

Related

What is the optimal way to import Redux selectors in React components?

I'm in a project where a migration from context to Redux is being made. I noticed a lot of components use the same selectors so I was wondering what is the best way to reuse them in order to save space in memory. Selectors are simple, there are no special operations during the import.
So far what we're doing looks like this:
export const myApp: React.FC<MyAppProps> = (props) => {
const dispatch = useAppDispatch()
const {myVar} = useAppSelector((state) => state.vars)
return (<div>...</div>)
}
We import the dispatch function in every component that uses it, together with any selectors we need.
Is there a way to optimize this process?
Thanks in advance.
I don't think there's any "savings in memory" to be had here.
You can certainly move the selector definitions into slice files, and import the selectors into the components. That's fine.
But that isn't going to affect "memory" usage at all.

Confusion with the way Redux selector is used

I was learning Redux and came across the concept of Redux selector. I got curious what that was and found out that it is a function that encapsulates the logic of slice of store state so that we can reuse it. Here is the code:
function mapStateToProps(state) {
return {
incompleteTodos: state.todos.filter((todo) => {
return !todo.completed
});
}
}
Becomes
function mapStateToProps(state) {
return {
incompleteTodos: getIncompleteTodos(state)
};
}
But the question I wanted to ask is that Is it true that when we use selector like this incompleteTodos: getIncompleteTodos(state) apart from reusability we also get memoization by default. Thus, we do not need to use reselect library. Is that true?
Short answer your question is No. By default properties in mapStateToProps is calculated every time when the component is updated, but there is some other solutions:
Reselect library which you mention, it's official package of Redux team so you can trust it.
You can use Redux Toolkit package which is also an official library and out of the box it also has Reselect.
You can use Redux Hook - useSelector which by default behaves like memorized property, so i guess this is what you are interested, in terms of default memorization.

Modify selector in redux saga without mutating state

When using a selector, I thought that I could do whatever I wanted with the variable without modifying the state, so I was surprised that the state became mutated.
So if this is wrong (in a redux saga):
const filters = yield select(state => state.filters.filters);
filters.terms['helloo'] = "mutated";
//send data with request
yield put(requestData(filters)
How come that first line is a direct reference to the state?
Anyway, if I try using Object.assign, it also mutates state:
const filters = Object.assign({}, yield select(state => state.filters.filters));
filters.terms['helloo'] = "mutated";
How do I create a selection that is a copy of the state?
There's truly no "magic" involved here. Redux's getState() is literally just return state, and both hand-written selectors and Reselect return whatever you have written the functions to return. So, in that example, filters is the actual object reference that's nested inside the store state, because that's what your function returned.
Per the Redux docs page on "Immutable Update Patterns", you need to copy all levels of nesting that you want to update. In your example, you're making a copy of filters, but not filters.terms, so terms is also still the original object that's in the store. You would need to make a copy of that as well, and modify the copy.

Result functions of type x => x are unnecessary?

There might be a gap in my understanding of how Reselect works.
If I understand it correctly the code beneath:
const getTemplates = (state) => state.templates.templates;
export const getTemplatesSelector = createSelector(
[getTemplates],
templates => templates
);
could just as well (or better), without loosing anything, be written as:
export const getTemplatesSelector = (state) => state.templates.templates;
The reason for this, if I understand it correctly, is that Reselect checks it's first argument and if it receives the exact same object as before it returns a cached output. It does not check for value equality.
Reselect will only run templates => templates when getTemplates returns a new object, that is when state.templates.templates references a new object.
The input in this case will be exactly the same as the input so no caching functionality is gained by using Reselect.
One can only gain performance from Reselect's caching-functionality when the function (in this case templates => templates) itself returns a new object, for example via .filter or .map or something similar. In this case though the object returned is the same, no changes are made and thus we gain nothing by Reselect's memoization.
Is there anything wrong with what I have written?
I mainly want to make sure that I correctly understand how Reselect works.
-- Edits --
I forgot to mention that what I wrote assumes that the object state.templates.templates immutably that is without mutation.
Yes, in your case reselect won't bring any benefit, since getTemplates is evaluated on each call.
The 2 most important scenarios where reselect shines are:
stabilizing the output of a selector when result function returns a new object (which you mentioned)
improving selector's performance when result function is computationally expensive

Reselect - does it ever make sense to create a memorized selector which is just used to get part of the state?

I have a normal selector which is just used to get part of the state:
export const getAllPosts = state => {
return state.posts;
};
If I use the reselect to wrap the selector:
import { createSelector } from 'reselect';
export const allPosts = createSelector(
getAllPosts,
(posts) => posts
);
Does it make any sense such as improving performance ? In my opinion, the wrapper is unnecessary.
No, it does not make sense to create a memoized selector just to get part of the state tree.
The reason is that connect will do it’s own shallow equality check for each prop passed in from mapStateToProps. If the prop returned by the selector passes that shallow equality check, along with the other props, then render will not be called unnecessarily. If the selector simply returned a part of the state tree and that part of the state tree had not been modified then a shallow equality check will be sufficient.
However, If the selector is computed from the results of other selectors then using createSelector is a good choice. Firstly, it provides a nice syntax for composing selectors. Secondly, if the computation of combining the selectors is potentially expensive you will get a performance benifit. Thirdly, if the selector was to return a new, but equivelent, object or array then the shallow equality check provided by connect would not be sufficient. In that case the memoization that createSelector provides would ensure that the same object or array instance was returned if the inputs had not changed and then the shallow equality check would be sufficient to avoid costly re-renders.
So for just exposing parts of the state tree createSelector doesn’t add anything.
For nearly all selectors that are computed from multiple parts of the state tree createSelector begins to add value. The amount of value that it adds varies based on the selector from just being easier to read up to ensuring you don’t re render the component tree unnecessarily.
In your case it does not make sense cause you just return the same reference from the store which is always shallow equal to itself (or it's previous state) unless you modify it.
If you imagine a different scenario for example a scenario where you store your entities in an object instead of an array in the store but you want to return an array to your Component then you need to derive data:
export const selectAllPosts = createSelector(
getAllPostsFromStore, // returns { 1: {...}, 2: {...} }
(allPosts) => Object.keys(allPosts).map(key => allPosts[key])
);
Now your selector turned into a performance boost cause it only computes the derived data when something in the store changes.
So my rule of thumb is: If you don't derive data, you don't need to memoize it.
No, that provides no real benefit.
What I've found is that my first-level selectors are simply plain functions, and any selectors that go deeper than that need to be memoized:
// assume state is: {first : {second {} } }
const selectFirst = state => state.first;
const selectSecond = createSelector(
selectFirst,
first => first.second
);

Resources