Adrian Faciu
Principal software engineer. Focused on front-end. Learning something new each day. Building things at WeVideo.
@adrianfaciu
@adrianfaciu
@adrianfaciu
@adrianfaciu
Redux is a predictable state container for JavaScript apps
@adrianfaciu
@adrianfaciu
@adrianfaciu
+
+
@adrianfaciu
@adrianfaciu
@adrianfaciu
@adrianfaciu
@adrianfaciu
@adrianfaciu
import { createAction, props }
from '@ngrx/store';
const logout = createAction(
'[Toolbar] Logout'
);
const login = createAction(
'[Login Page] Login',
props<{ username: string; password: string }>()
);
@adrianfaciu
import { createAction, props }
from '@ngrx/store';
const logout = createAction(
'[Toolbar] Logout'
);
const login = createAction(
'[Login Page] Login',
props<{ username: string; password: string }>()
);
@adrianfaciu
import { createAction, props }
from '@ngrx/store';
const logout = createAction(
'[Toolbar] Logout'
);
const login = createAction(
'[Login Page] Login',
props<{ username: string; password: string }>()
);
@adrianfaciu
import { createReducer, on } from '@ngrx/store';
import * as LoginActions from './actions';
export const reducer = createReducer(
initialState,
on(LoginActions.logout,
() => ({ ...state, username: ''})),),
on(LoginActions.login,
(state, { username }) => ({ ...state, username })),
);
@adrianfaciu
import { createReducer, on } from '@ngrx/store';
import * as LoginActions from './actions';
export const reducer = createReducer(
initialState,
on(LoginActions.logout,
() => ({ ...state, username: ''})),
on(LoginActions.login,
(state, { username }) => ({ ...state, username })),
);
@adrianfaciu
import { createEffect } from '@ngrx/effects';
export class UserEffects {
userLogin$ = createEffect(() => this.actions$.pipe(
ofType(UserActions.login),
map(({user}) => AuthApiActions.login({user}))
))
}
@adrianfaciu
import { createEffect } from '@ngrx/effects';
export class UserEffects {
userLogin$ = createEffect(() => this.actions$.pipe(
ofType(UserActions.login),
map(({user}) => AuthApiActions.login({user})),
));
}
@adrianfaciu
@adrianfaciu
@NgModule({
imports: [
StoreModule.forRoot(reducerMap, {
runtimeChecks: {
strictImmutability: true,
strictStateSerializability: true,
strictActionSerializability: true,
},
}),
],
})
export class AppModule {}
@adrianfaciu
@NgModule({
imports: [
StoreModule.forRoot(reducers, {
runtimeChecks: {
strictImmutability: true,
strictStateSerializability: true,
strictActionSerializability: true,
},
}),
],
})
export class AppModule {}
@adrianfaciu
@NgModule({
imports: [
StoreModule.forRoot(reducers, {
runtimeChecks: {
strictImmutability: true,
strictStateSerializability: true,
strictActionSerializability: true,
},
}),
],
})
export class AppModule {}
@adrianfaciu
const logout = createAction(
'[Toolbar] Logout'
);
const login = createAction(
'[Login Screen] Login'
);
const fetchUsers = createAction(
'[Admin Users List] Fetch users'
);
@adrianfaciu
@adrianfaciu
// products.actions.ts
const fetch =
createAction('[Product List] Fetch');
const fetchSuccess =
createAction('[Product List] Fetch Success');
const fetchFail =
createAction('[Product List] Fetch Fail');
const fetchCount =
createAction('[Product List] Fetch Count');
@adrianfaciu
@adrianfaciu
showSaveMessage$ = createEffect(
() =>
this.actions$.pipe(
ofType(saveSuccess),
tap(() => this.snackBar.open(
'Saved!',
null,
{ duration: 1000 }))
),
{
dispatch: false,
}
);
@adrianfaciu
showSaveMessage$ = createEffect(
() =>
this.actions$.pipe(
ofType(saveSuccess),
tap(() => this.snackBar.open(
'Saved!',
null,
{ duration: 1000 }))
),
{
dispatch: false,
}
);
@adrianfaciu
showSaveMessage$ = createEffect(
() =>
this.actions$.pipe(
ofType(saveSuccess),
tap(() => this.snackBar.open(
'Saved!',
null,
{ duration: 1000 }))
),
{
dispatch: false,
}
);
@adrianfaciu
@adrianfaciu
showSaveMessage$ = createEffect(
() =>
fromEvent(document, 'click').pipe(
map(() => UserActions.click())
)
);
@adrianfaciu
showSaveMessage$ = createEffect(
() =>
fromEvent(document, 'click').pipe(
map(() => UserActions.click())
)
);
@adrianfaciu
@adrianfaciu
loadEmployees$ = createEffect(() =>
this.actions$.pipe(
ofType(fetch),
switchMap(() =>
this.employeeService.getAll().pipe(
map(employees => fetchSuccess({ employees })),
catchError(() => of(fetchError()))
)
)
)
);
@adrianfaciu
@adrianfaciu
loadEmployees$ = createEffect(() =>
this.actions$.pipe(
ofType(fetch),
switchMap(() =>
this.employeeService.getAll().pipe(
map(employees => fetchSuccess({ employees })),
catchError(() => of(fetchError()))
)
)
)
);
@adrianfaciu
@adrianfaciu
deleteEmployees$ = createEffect(() =>
this.actions$.pipe(
ofType(delete),
switchMap(({id}) =>
this.employeeService.delete(id)
.pipe(
map(employees => deleteSuccess()),
catchError(() => of(deleteError()))
)
)
)
);
@adrianfaciu
Pure functions, used to get slices of state
@adrianfaciu
import { createSelector } from '@ngrx/store';
export const selectFeature =
(state: AppState) => state.feature;
export const selectCount = createSelector(
selectFeature,
(state: FeatureState) => state.counter
);
@adrianfaciu
import { createSelector } from '@ngrx/store';
export const selectFeature =
(state: AppState) => state.feature;
export const selectCount = createSelector(
selectFeature,
(state: FeatureState) => state.counter
);
@adrianfaciu
@adrianfaciu
@adrianfaciu
@adrianfaciu
@adrianfaciu
@adrianfaciu
export const getCount = createSelector(
getCounterValue,
(counter, props) => counter * props.multiply
);
this.counter =
this.store.select(getCount, { multiply: 2 });
@adrianfaciu
export const getCount = createSelector(
getCounterValue,
(counter, props) => counter * props.multiply
);
this.counter =
this.store.select(getCount, { multiply: 2 });
@adrianfaciu
@adrianfaciu
@adrianfaciu
@adrianfaciu
@adrianfaciu
export const reducer = createReducer(
initialState,
on(ScoreboardPageActions.homeScore,
(state) => {...state, home: state.home + 1}),
on(ScoreboardPageActions.awayScore,
(state) => {...state, away: state.away + 1}),
on(ScoreboardPageActions.reset,
(state, {away, home}) => {...state, away, home}),
);
@adrianfaciu
avoid deeply nested objects
@adrianfaciu
avoid deeply nested objects
don't duplicate
@adrianfaciu
avoid deeply nested objects
don't duplicate
store as objects, not as arrays
@adrianfaciu
{
articles: {
123: {
id: 123,
author: 1,
title: "My awesome blog post",
comments: [ 324 ]
}
},
users: {
1: { id: 1, name: "Paul" },
2: { id: 2, name: "Nicole" }
},
comments: {
324: { id: 324, author: 2 }
}
}
@adrianfaciu
{
articles: {
123: {
id: 123,
author: 1,
title: "My awesome blog post",
comments: [ 324 ]
}
},
users: {
1: { id: 1, name: "Paul" },
2: { id: 2, name: "Nicole" }
},
comments: {
324: { id: 324, author: 2 }
}
}
@adrianfaciu
{
articles: {
123: {
id: 123,
author: 1,
title: "My awesome blog post",
comments: [ 324 ]
}
},
users: {
1: { id: 1, name: "Paul" },
2: { id: 2, name: "Nicole" }
},
comments: {
324: { id: 324, author: 2 }
}
}
@adrianfaciu
@adrianfaciu
@adrianfaciu
@adrianfaciu
@adrianfaciu
@adrianfaciu
@adrianfaciu
By Adrian Faciu
Principal software engineer. Focused on front-end. Learning something new each day. Building things at WeVideo.