How to decipher ngrx API - ngrx

Can someone help me to go through this definition step by step?
select<T, Props, K>(pathOrMapFn: string | ((state: T, props?: Props) => any), propsOrPath: string | Props, ...paths: string[])
I don't get the hang of it...

It's the definition of the a selector.
T: the incoming state
Props: if you're calling a selector with props
K: the result of the selector
pathOrMapFn can either be the path to the state or a createSelector
propsOrPath can either be the path to the state or the props
...paths: string[] the rest of the path
With path to state I mean: select('featureState', 'persons', 'entities')

Related

Redux Toolkit matcher to determine if exists in state

I have a large reducer where I'm storing all data entities in a flat structure.
I want to seperate this into 2 seperate reducers so that some of the entities are persisted with Redux Persist and some are not.
To acheive this, I'm trying to add a matcher to detect if the state already has the entity and reject if not.
i.e.
//these cases are used by both reducers
builder
.addCase(update, (state, action) => {})
.addCase(copy, (state, action) => {})
.addCase(clone, (state, action) => {})
.addMatcher(isEntityAction, matcher);
function isEntityAction(action: AnyAction): action is PayloadAction {
return !!action.payload?.entity;
}
function matcher(state, action: AnyAction): action is PayloadAction<any> {
return state[action.payload?.entity?.entityType] !== undefined;
}
However the matcher is having no effect.
What's the right way to go about this? Thanks
You are misinterpreting addMatcher here.
The sigature is addMatcher(matcher, reducer) - the matcher can only say "I want to handle this action" or "I do not want to handle it" - it cannot look at the state. It can also not "reject" something.

What is a difference between mapStateToProps,mapDispatchToProps types and selector in reactnative

I am new to react native with redux. I am trying to figure out how all the pieces in react-native redux integration. The one thing giving me trouble is understanding the difference types and selector give me more details.
MapStateToProps -> has his name say, you can map state objects to props. Example:
You have a store like this:
{
name:'paul',
surname:'watson'
}
Then you need show in your component the name, so in your container you can access to this data stored in store with mapstatetoprops, like this:
const mapStateToProps = (state, ownProps) => ({
myname: state.name,
})
MapDispatchToProps -> thats when you need dispatch an action, you map an action to a prop to you can use in your component
You have an action like:
const setMyName = payload => ({
type: SET_MY_NAME,
payload,
})
then you need update your name in store when user click something throw this action, so you can map this action in a prop to call like updateName('pepito') with mapDispatchToProps, like this:
const mapDispatchToProps = {
updateName: setMyName,
}
Selectors -> it's just an abstraction code, selectors make your life more easy.
Selectors are functions that take Redux state as an argument and return some data to pass to the component, like this:
const getDataType = state => state.editor.dataType;
Thats a basic concepts, you should read oficial document and search, in internet have a lot of articles about this.

Why the reselect createSelector necessary in this #ngrx example?

What does the following code snippet do? It is taken from this file.
export const getCollectionLoading = createSelector(getCollectionState, fromCollection.getLoading);
The fromCollection.getLoading has only either true or false value, so can there be any optimization achieved by using the createSelector?
in
export const getCollectionLoaded = createSelector(getCollectionState, fromCollection.getLoaded);
export const getCollectionLoading = createSelector(getCollectionState, fromCollection.getLoading);
export const getCollectionBookIds = createSelector(getCollectionState, fromCollection.getIds);
According to the example app's comments:
/**
* Every reducer module exports selector functions, however child reducers
* have no knowledge of the overall state tree. To make them useable, we
* need to make new selectors that wrap them.
**/
For example in reducers/collections.ts the selectors at the bottom of the file only reference the collection slice:
export const getLoaded = (state: State) => state.loaded;
export const getLoading = (state: State) => state.loading;
export const getIds = (state: State) => state.ids;
These collection selectors can't be used with state.select() because state.select expects to work with the whole AppState. Therefore in the reducers/index.ts the selector is then wrapped with another selector so that it does work with the whole AppState:
export const getCollectionLoading = createSelector(getCollectionState, fromCollection.getLoading);
Back to your question: why is it necessary to use reselect for this. Reselect in this case isn't providing any optimizations. So the main purpose of reselect is that it provides the ability to compose selectors together.
By using this composition feature we can make collections.ts only have selectors for the collections slice. Then in index.ts we can have selectors at the AppState level. Furthermore we can have selectors that work across different slices of the store such as this one:
/**
* Some selector functions create joins across parts of state. This selector
* composes the search result IDs to return an array of books in the store.
*/
export const getSearchResults = createSelector(getBookEntities,
getSearchBookIds, (books, searchIds) => {
return searchIds.map(id => books[id]);
});
Yes, there may be performance gains. If fromCollection.getLoading computation is expensive, reselect would avoid useless recalculations until getCollectionState keeps returning the same value.

React Redux - state returned in mapStateToProps has reducer names as properties?

I have 2 reducers that are combined in a Root Reducer, and used in a store.
First reducer 'AllTracksReducer" is supposed to return an object and the second 'FavoritesReducer' an array.
When I create a container component and a mapStateToProps method in connect, for some reason the returned state of the store is an object with 2 reducer objects which hold data, and not just an object containing correposding data, as expected.
function mapStateToProps(state) {
debugger:
console.dir(state)
//state shows as an object with 2 properties, AllTracksReducer and FavoritesReducer.
return {
data: state.AllTracksReducer.data,
isLoading: state.AllTracksReducer.isLoading
}
}
export default connect(mapStateToProps)(AllTracksContainer);
so, in mapStateToProps, to get to the right state property, i have to say
state.AllTracksReducer.data... But I was expecting the data to be available directly on the state object?
Yep, this is a common semi-mistake. It's because you're using likely using ES6 object literal shorthand syntax to create the object you pass to combineReducers, so the names of the imported variables are also being used to define the state slice names.
This issue is explained in the Redux docs, at Structuring Reducers - Using combineReducers.
Create some selectors that receive the whole state (or the reducer-specific state) and use it in your mapStateToProps function. Indeed the name you define when you combineReducers will be the topmost state keys, so your selectors should take that into account:
const getTracks = (state) => state.allTracks.data
const isLoading = state => state.allTracks.isLoading
This assumes you combine your reducers with allTracks as they key like here:
combineReducers({
allTracks: allTracksReducer
})
And then you can use those selectors in your mapper, like
const mapStateToProps = state => ({
isLoading: isLoading(state),
tracks: getTracks(state)
})
There's a delicate link between your combineReducers call and your selectors. If you change the state key name you'll have to update your selectors accordingly.
It helps me to think of action creators as "setters" and selectors as "getters", with the reducer function being simply the persistence part. You call your setters (dispatching action creators) when you want to modify your state, and use your selectors as shown to get the current state and pass it as props to your components.
Well, that's how it supposed to work. When you're using combineReducers, you're literally mapping the name of a reducer to the reducer function.
If it bothers you, I would suggest a little syntactical magic if you're using es2016 (though it seems you're not) like so:
function mapStateToProps(state) {
const { data, isLoading } = state.allTracksReducer;
return {
data: data,
isLoading: isLoading
}
}
export default connect(mapStateToProps)(AllTracksContainer);
Remember, state is the one source of truth that possesses all your reducers.

Flow doesn't infer type correctly

I define an multiple subtypes in the Action creator in redux:
Action creator:
export type Action = { type: "SELECT", index: number } | { type: "OTHER" };
Reducer:
module.exports = (state: string = "", action: Action): string => {
switch (action.type) {
case "SELECT":
return action.index;
default:
return state;
}
};
but if I define SELECT in a constant const select = "SELECT" and implement it in the code above I obtain an error message:
property `index`. Property not found in object type
Note: Taking flow-pattern as it is F8 app:
https://github.com/fbsamples/f8app/blob/master/js/actions/types.js
How should implement it by avoiding having "SELECT" keyword both in the action and in the reducer?
You would normally have another constant with the action type, which would be used for both your action and reducer.
const SELECT = 'SELECT';
or even better (to avoid any conflicts):
const SELECT = 'redux/<module>/SELECT';
In the same action file or in another (that's totally up to you). Then just export like export const SELECT, and import like import { SELECT } from './constants'.
You should also take a look at redux-ducks, might be of your interest.
EDIT:
They use bitwise OR to group all possible different action cases. That helps testing whether the code is syntactically correct with flow (by setting their dispatched actions to match type Action). See their full explanation here.
That does not take away the fact that they have to dispatch the action with their desired action type though. login

Resources