Ngrx 6.1.0 - Select is deprecated - What is the new syntax? - ngrx

The following ngrx select is deprecated.
this.store.select(state => state.academy.academy).subscribe((academy) => {
this.academy = academy;
});
I found this at store.d.ts
#deprecated from 6.1.0. Use the pipeable `select` operator instead.
So... what's the correct syntax?
I try
this.store.pipe(select(state => state.academy.academy).subscribe((academy) => {
this.academy = academy;
}))
Error: Cannot find name 'select'. Did you mean 'onselect'?

import {Component, OnInit} from '#angular/core';
import {Store, select} from '#ngrx/store';
import {AppState} from '../../../../../app.state';
#Component({
selector: 'app-layout',
templateUrl: './layout.component.html',
styleUrls: ['./layout.component.scss']
})
export class PageLayoutComponent implements OnInit {
academy;
constructor(
private store: Store<AppState>
) {
}
ngOnInit() {
this.store.pipe(select((state: any) => state.academy.academy)).subscribe((academy) => {
this.academy = academy;
});
}
}

As per NgRx 7, the select method is un-deprecated.
For more info, see the associated Pull Request.

As #Michalis mentioned, just get select from #ngrx/store.
Selectors empower you to compose a read model for your application state. In terms of the CQRS architectural pattern, NgRx separates the read model (selectors) from the write model (reducers). An advanced technique is to combine selectors with RxJS pipeable operators.
This feature was added in v5.0.0, and since then this.store.select() has been deprecated. However, notice for the same is added in release v6.1.0. As Store<T> itself extends Observable<T>, it returns observable which can easily be subscribed using .subscribe() or can be manipulated/transformed using different patch operators.
RxJS introduced pipable operators and .pipe() in v5.5. There is also a pipe utility function that can be used to build reusable pipeable operators. In release v5, with the help of pipe() custom select operator is built. Check out this link or basic example(ignore empty state) is given beneath, to learn more.
import { select } from '#ngrx/store';
import { pipe } from 'rxjs';
import { filter } from 'rxjs/operators';
export const selectFilteredState = pipe(
select('sliceOfState'),
filter(state => state !== undefined)
);
store.pipe(selectFilteredState ).subscribe(/* .. */);

Related

Issues when upgrading from ngrx 7 to ngrx 10

could someone please help me to resolve this issue; I have upgraded the ngrx version on my Angular app from version 7 to 10, then when I have tried to launch the application i got this error :
Overload 1 of 8, '(mapFn: (state: unknown, props: unknown) => unknown, props?: unknown): (source$: Observable<unknown>) => Observable<unknown>', gave the following error.
Argument of type '"userDetails"' is not assignable to parameter of type '(state: unknown, props: unknown) => unknown'.
Overload 2 of 8, '(key: never): (source$: Observable<unknown>) => Observable<never>', gave the following error.
Argument of type '"userDetails"' is not assignable to parameter of type 'never'.
The code were compiled on the Version 7 :
import { select } from '#ngrx/store';
import { pipe } from 'rxjs';
import { filter } from 'rxjs/operators';
export const selectuserDetails = pipe(
select('userDetails'),
filter(uds => uds && uds.isFetched)
);
What shall i change to fix this issue please, and compile this code on the version 10!
Thank you.
You are passing a string to select(). Instead, import you selector and pass that:
import { select } from '#ngrx/store';
import { pipe } from 'rxjs';
import { filter } from 'rxjs/operators';
import * as MySelectors from 'path/to/selectors'
export const selectuserDetails = pipe(
select(MySelectors.userDetails),
filter(uds => uds && uds.isFetched)
);
Here is the relevant page in the docs:
https://ngrx.io/guide/store/selectors

Using refs with react-redux 6.0.0 and decorators

I have the following component:
export default
#connect(null, dispatch => ({ dispatch }))
class MyComponent extends React.PureComponent {
}
And I have a component wrapping it:
export default class MyWrapper extends React.PureComponent {
comp = React.createRef();
render() {
return <MyComponent ref={this.comp}/>
}
}
How do I access MyComponent using refs?
I tried {withRef: true}, then tried {forwardRef: true} and got all sorts of errors.
Per the React-Redux connect docs, you need to pass {forwardRef : true} as an option to connect:
connect(mapState, mapDispatch, mergeProps, {forwardRef : true}
This is the same whether you're using connect as a separate function, or as a decorator.
On which note: for reference, we do not recommend using connect as a decorator.
The problem is with "react-redux": "7.0.0". The connect function has been implemented as a functional react component, so #decorators is not working anymore.

Javascript ES6 How to convert a const function to a function

Trying to use vuexfire for Firebase bindings, the documentation state to insert the following action for binding
const setTodosRef = firebaseAction(({ bindFirebaseRef, unbindFirebaseRef }, { ref }) => {
// bunding will automatically unbind any previously bound ref so you
// don't need to unbind before binding over an existing bound key
bindFirebaseRef('todos', ref)
// it is possible to unbind a bound key at any time
unbindFirebaseRef('todos')
})
In my store root.js , all the actions are written with the following pattern
/**
* Import Dependency
*/
import * as types from './mutation_types'
import i18n from '#/locales'
import * as firebase from 'firebase'
import { firebaseMutations, firebaseAction } from 'vuexfire'
setTodosRef ( ) {
bindFirebaseRef('todos', ref)
unbindFirebaseRef('todos')
}
How can I pass the parameters to the function ?
in order to call
this.$store.dispatch('setTodosRef', db.ref('todos'))
setTodosRef (firebaseAction(({ bindFirebaseRef, unbindFirebaseRef }, { ref })) { ... }
doesn't work...
Syntax Error: Unexpected token, expected "," (119:29)
thanks for feedback
UPDATE
I removed the syntax error using
setTodosRef: firebaseAction(({ bindFirebaseRef, unbindFirebaseRef }, ref) => {
bindFirebaseRef('todos', ref)
unbindFirebaseRef('todos')
})
but I am not sure that's correct... ?
Your store actions are going to take two arguments. The first is a context object passed by vuex and is typically dereferenced. I don't have all of your code, so I can't write an exact method for you, but it needs to be something like this (assuming es6):
setTodosRef({ commit }, todos) {
commit(types.SET_TODOS, { todos })
}
Then you would have a mutation that handles the commit. It also receives an injected parameter as the first argument from vuex, then you provide the data in the second argument like:
[types.SET_TODOS](state, { todos }) {
state.todos = todos
}
https://vuex.vuejs.org/guide/actions.html

How to return a map of reducers in getReducers(): ActionReducerMap<fromFeature.State>?

I'm trying to inject feature reducers when composing state through NgRx feature modules.
import { NgModule, InjectionToken } from '#angular/core';
import { StoreModule, ActionReducerMap } from '#ngrx/store';
import * as fromFeature from './reducers';
export const FEATURE_REDUCER_TOKEN = new InjectionToken<ActionReducerMap<fromFeature.State>>('Feature Reducers');
What I am supposed to return here?
export function getReducers(): ActionReducerMap<fromFeature.State> {
// map of reducers
return {
};
}
I tried
export function getReducers(): ActionReducerMap<fromFeature.State> {
// map of reducers
return {
reducerA: FeatureAReducer
};
}
But it gives the error Object literal may only specify known properties.
The rest of module code:
#NgModule({
imports: [
StoreModule.forFeature('feature', FEATURE_REDUCER_TOKEN),
],
providers: [
{
provide: FEATURE_REDUCER_TOKEN,
useFactory: getReducers
}
]
})
export class FeatureModule { }
I thought that each reducer, whether it is root or feature reducer, returns a new state object. But actually it doesn't. What feature reducer does, it returns only the segment of the state which it updates.
From the ngrx/platform/example-app:
we treat each reducer like a table in a database. This means our
top level state interface is just a map of keys to inner state types.

Call sub-reducer in default block of a parent reducer

Is it ok to have a reducer calling sub-reducers in its default block?
function aReducer(state = {}, action) {
switch(action.type) {
case XYZ:
... // know what to do
default:
// don't know this action, let's delegate to the children
return {
sub1: subReducer1(state.sub1, action),
sub2: subReducer2(state.sub2, action)
}
}
}
Yes, that's absolutely legal and reasonable to do.
You might want to read through the Redux docs section on "Structuring Reducers" for further ideas on how you can organize reducer logic as well.
You can put all the reducers in a common folder and inside that, you can combine the separate reducers into a single one like the following code.
import { combineReducers } from 'redux'
import Reducer1 from './Reducer1.js'
import Reducer2 from './Reducer2.js'
export default combineReducers( { Reducer1, Reducer2,... } )
and use the following code to use that as a single reducer.
import reducers from '../../reducers'(reducer's root folder name/path)
let store = createStore( reducers );

Resources