Skip to content

Commit

Permalink
feat(store): change createReducer to avoid generic (#1796)
Browse files Browse the repository at this point in the history
  • Loading branch information
alex-okrushko authored and brandonroberts committed Apr 24, 2019
1 parent 2b83bef commit 8f2cb7b
Show file tree
Hide file tree
Showing 11 changed files with 129 additions and 143 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ export const initialState: State = adapter.getInitialState({
// additional entity state properties
});

const <%= camelize(name) %>Reducer = createReducer<State>([
const <%= camelize(name) %>Reducer = createReducer(
initialState,
on(<%= classify(name) %>Actions.add<%= classify(name) %>,
(state, action) => adapter.addOne(action.<%= camelize(name) %>, state)
),
Expand Down Expand Up @@ -44,7 +45,7 @@ const <%= camelize(name) %>Reducer = createReducer<State>([
on(<%= classify(name) %>Actions.clear<%= classify(name) %>s,
state => adapter.removeAll(state)
),
], initialState);
);

export function reducer(state: State | undefined, action: Action) {
return <%= camelize(name) %>Reducer(state, action);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@ export const initialState: State = {

};

const <%= camelize(name) %>Reducer = createReducer<State>([
const <%= camelize(name) %>Reducer = createReducer(
initialState,
<% if(feature) { %>
on(<%= classify(name) %>Actions.load<%= classify(name) %>s, state => state),
<% if(api) { %> on(<%= classify(name) %>Actions.load<%= classify(name) %>sSuccess, (state, action) => state),
on(<%= classify(name) %>Actions.load<%= classify(name) %>sFailure, (state, action) => state),
<% } %><% } %>
], initialState);
);

export function reducer(state: State | undefined, action: Action) {
return <%= camelize(name) %>Reducer(state, action);
Expand Down
6 changes: 3 additions & 3 deletions modules/schematics/src/reducer/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ describe('Reducer Schematic', () => {
expect(fileContent).toMatch(
/export function reducer\(state: State | undefined, action: Action\) {/
);
expect(fileContent).toMatch(/const fooReducer = createReducer<State>\(/);
expect(fileContent).toMatch(/const fooReducer = createReducer\(/);
});

it('should create an reducer function in a feature using createReducer', () => {
Expand All @@ -218,7 +218,7 @@ describe('Reducer Schematic', () => {
expect(fileContent).toMatch(
/export function reducer\(state: State | undefined, action: Action\) {/
);
expect(fileContent).toMatch(/const fooReducer = createReducer<State>\(/);
expect(fileContent).toMatch(/const fooReducer = createReducer\(/);
expect(fileContent).toMatch(/on\(FooActions.loadFoos, state => state\)/);
});

Expand All @@ -235,7 +235,7 @@ describe('Reducer Schematic', () => {
expect(fileContent).toMatch(
/export function reducer\(state: State | undefined, action: Action\) {/
);
expect(fileContent).toMatch(/const fooReducer = createReducer<State>\(/);
expect(fileContent).toMatch(/const fooReducer = createReducer\(/);
expect(fileContent).toMatch(
/on\(FooActions.loadFoosSuccess, \(state, action\) => state\)/
);
Expand Down
16 changes: 7 additions & 9 deletions modules/store/spec/reducer_creator.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,10 @@ import {on} from './modules/store/src/reducer_creator';
bar?: number;
}

const fooBarReducer = createReducer<State>(
[
on(foo, (state, { foo }) => ({ ...state, foo })),
on(bar, (state, { bar }) => ({ ...state, bar })),
],
{}
const fooBarReducer = createReducer(
{} as State,
on(foo, (state, { foo }) => ({ ...state, foo })),
on(bar, (state, { bar }) => ({ ...state, bar }))
);

expect(typeof fooBarReducer).toEqual('function');
Expand All @@ -72,9 +70,9 @@ import {on} from './modules/store/src/reducer_creator';
it('should support reducers with multiple actions', () => {
type State = string[];

const fooBarReducer = createReducer<State>(
[on(foo, bar, (state, { type }) => [...state, type])],
[]
const fooBarReducer = createReducer(
[] as State,
on(foo, bar, (state, { type }) => [...state, type])
);

expect(typeof fooBarReducer).toEqual('function');
Expand Down
4 changes: 2 additions & 2 deletions modules/store/src/reducer_creator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ export function on(
}

export function createReducer<S>(
ons: On<S>[],
initialState: S
initialState: S,
...ons: On<S>[]
): ActionReducer<S> {
const map = new Map<string, ActionReducer<S>>();
for (let on of ons) {
Expand Down
10 changes: 4 additions & 6 deletions projects/example-app/src/app/auth/reducers/auth.reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,10 @@ export const initialState: State = {
user: null,
};

export const reducer = createReducer<State>(
[
on(AuthApiActions.loginSuccess, (state, { user }) => ({ ...state, user })),
on(AuthActions.logout, () => initialState),
],
initialState
export const reducer = createReducer(
initialState,
on(AuthApiActions.loginSuccess, (state, { user }) => ({ ...state, user })),
on(AuthActions.logout, () => initialState)
);

export const getUser = (state: State) => state.user;
36 changes: 17 additions & 19 deletions projects/example-app/src/app/auth/reducers/login-page.reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,24 @@ export const initialState: State = {
pending: false,
};

export const reducer = createReducer<State>(
[
on(LoginPageActions.login, state => ({
...state,
error: null,
pending: true,
})),
export const reducer = createReducer(
initialState,
on(LoginPageActions.login, state => ({
...state,
error: null,
pending: true,
})),

on(AuthApiActions.loginSuccess, state => ({
...state,
error: null,
pending: false,
})),
on(AuthApiActions.loginFailure, (state, { error }) => ({
...state,
error,
pending: false,
})),
],
initialState
on(AuthApiActions.loginSuccess, state => ({
...state,
error: null,
pending: false,
})),
on(AuthApiActions.loginFailure, (state, { error }) => ({
...state,
error,
pending: false,
}))
);

export const getError = (state: State) => state.error;
Expand Down
54 changes: 26 additions & 28 deletions projects/example-app/src/app/books/reducers/books.reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,34 +41,32 @@ export const initialState: State = adapter.getInitialState({
selectedBookId: null,
});

export const reducer = createReducer<State>(
[
/**
* The addMany function provided by the created adapter
* adds many records to the entity dictionary
* and returns a new state including those records. If
* the collection is to be sorted, the adapter will
* sort each record upon entry into the sorted array.
*/
on(
BooksApiActions.searchSuccess,
CollectionApiActions.loadBooksSuccess,
(state, { books }) => adapter.addMany(books, state)
),
/**
* The addOne function provided by the created adapter
* adds one record to the entity dictionary
* and returns a new state including that records if it doesn't
* exist already. If the collection is to be sorted, the adapter will
* insert the new record into the sorted array.
*/
on(BookActions.loadBook, (state, { book }) => adapter.addOne(book, state)),
on(ViewBookPageActions.selectBook, (state, { id }) => ({
...state,
selectedBookId: id,
})),
],
initialState
export const reducer = createReducer(
initialState,
/**
* The addMany function provided by the created adapter
* adds many records to the entity dictionary
* and returns a new state including those records. If
* the collection is to be sorted, the adapter will
* sort each record upon entry into the sorted array.
*/
on(
BooksApiActions.searchSuccess,
CollectionApiActions.loadBooksSuccess,
(state, { books }) => adapter.addMany(books, state)
),
/**
* The addOne function provided by the created adapter
* adds one record to the entity dictionary
* and returns a new state including that records if it doesn't
* exist already. If the collection is to be sorted, the adapter will
* insert the new record into the sorted array.
*/
on(BookActions.loadBook, (state, { book }) => adapter.addOne(book, state)),
on(ViewBookPageActions.selectBook, (state, { id }) => ({
...state,
selectedBookId: id,
}))
);

/**
Expand Down
64 changes: 31 additions & 33 deletions projects/example-app/src/app/books/reducers/collection.reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,41 +17,39 @@ const initialState: State = {
ids: [],
};

export const reducer = createReducer<State>(
[
on(CollectionPageActions.loadCollection, state => ({
...state,
loading: true,
})),
on(CollectionApiActions.loadBooksSuccess, (state, { books }) => ({
loaded: true,
loading: false,
ids: books.map(book => book.id),
})),
// Supports handing multiple types of actions
on(
CollectionApiActions.addBookSuccess,
CollectionApiActions.removeBookFailure,
(state, { book }) => {
if (state.ids.indexOf(book.id) > -1) {
return state;
}
return {
...state,
ids: [...state.ids, book.id],
};
export const reducer = createReducer(
initialState,
on(CollectionPageActions.loadCollection, state => ({
...state,
loading: true,
})),
on(CollectionApiActions.loadBooksSuccess, (state, { books }) => ({
loaded: true,
loading: false,
ids: books.map(book => book.id),
})),
// Supports handing multiple types of actions
on(
CollectionApiActions.addBookSuccess,
CollectionApiActions.removeBookFailure,
(state, { book }) => {
if (state.ids.indexOf(book.id) > -1) {
return state;
}
),
on(
CollectionApiActions.removeBookSuccess,
CollectionApiActions.addBookFailure,
(state, { book }) => ({
return {
...state,
ids: state.ids.filter(id => id !== book.id),
})
),
],
initialState
ids: [...state.ids, book.id],
};
}
),
on(
CollectionApiActions.removeBookSuccess,
CollectionApiActions.addBookFailure,
(state, { book }) => ({
...state,
ids: state.ids.filter(id => id !== book.id),
})
)
);

export const getLoaded = (state: State) => state.loaded;
Expand Down
58 changes: 28 additions & 30 deletions projects/example-app/src/app/books/reducers/search.reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,36 +18,34 @@ const initialState: State = {
query: '',
};

export const reducer = createReducer<State>(
[
on(FindBookPageActions.searchBooks, (state, { query }) => {
return query === ''
? {
ids: [],
loading: false,
error: '',
query,
}
: {
...state,
loading: true,
error: '',
query,
};
}),
on(BooksApiActions.searchSuccess, (state, { books }) => ({
ids: books.map(book => book.id),
loading: false,
error: '',
query: state.query,
})),
on(BooksApiActions.searchFailure, (state, { errorMsg }) => ({
...state,
loading: false,
error: errorMsg,
})),
],
initialState
export const reducer = createReducer(
initialState,
on(FindBookPageActions.searchBooks, (state, { query }) => {
return query === ''
? {
ids: [],
loading: false,
error: '',
query,
}
: {
...state,
loading: true,
error: '',
query,
};
}),
on(BooksApiActions.searchSuccess, (state, { books }) => ({
ids: books.map(book => book.id),
loading: false,
error: '',
query: state.query,
})),
on(BooksApiActions.searchFailure, (state, { errorMsg }) => ({
...state,
loading: false,
error: errorMsg,
}))
);

export const getIds = (state: State) => state.ids;
Expand Down
14 changes: 5 additions & 9 deletions projects/example-app/src/app/core/reducers/layout.reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,11 @@ const initialState: State = {
showSidenav: false,
};

export const reducer = createReducer<State>(
[
// Explicit 'State' return type for the 'on' functions is needed because
// otherwise the return types are narrowed to showSidenav: false instead of
// showSidenav: boolean (that State is asking for).
on(LayoutActions.closeSidenav, state => ({ showSidenav: false })),
on(LayoutActions.openSidenav, state => ({ showSidenav: true })),
],
initialState
export const reducer = createReducer(
initialState,
// Even thought the `state` is unused, it helps infer the return type
on(LayoutActions.closeSidenav, state => ({ showSidenav: false })),
on(LayoutActions.openSidenav, state => ({ showSidenav: true }))
);

export const getShowSidenav = (state: State) => state.showSidenav;

0 comments on commit 8f2cb7b

Please sign in to comment.