Skip to content

Commit dd21108

Browse files
No redux-actions posts store
1 parent 1231f8a commit dd21108

File tree

6 files changed

+113
-36
lines changed

6 files changed

+113
-36
lines changed

src/store/interfaces.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ export interface IAction {
55
}
66

77
export interface IPayloadAction<Payload> extends IAction {
8-
payload: Payload;
8+
payload?: Payload;
99
}
1010

1111
export interface IErrorAction extends IAction {
@@ -24,7 +24,3 @@ export interface INormalized<Entities, Result> {
2424
entities: Entities;
2525
result: Result;
2626
}
27-
28-
export interface IReducerMap<TState, TAction> {
29-
[action: string]: (state: TState, action: TAction) => TState;
30-
}

src/store/posts/actions-spec.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { expect } from 'chai';
2+
import { REQUEST_POSTS, RECEIVE_POSTS, requestPosts, receivePosts } from './';
3+
4+
describe('posts / actions', () => {
5+
it('requestPosts', () =>
6+
expect(requestPosts()).to.eql({
7+
type: REQUEST_POSTS
8+
})
9+
);
10+
11+
it('receivePosts', () =>
12+
expect(receivePosts({ data: [] })).to.eql({
13+
type: RECEIVE_POSTS,
14+
payload: { data: [] }
15+
})
16+
);
17+
});

src/store/posts/actions.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { REQUEST_POSTS, RECEIVE_POSTS, IPostsJSON, IPostsAction } from './types';
2-
import { IAction, IThunk, IPayloadAction } from '../interfaces';
2+
import { IThunk } from '../interfaces';
33
import fetch from 'isomorphic-fetch';
44

5-
export function requestPosts(): IAction {
5+
export function requestPosts(): IPostsAction {
66
return { type: REQUEST_POSTS };
77
}
88

src/store/posts/reducer-spec.ts

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,56 @@
11
import { expect } from 'chai';
2-
import { postsReducer, fetchPosts, receivePosts, requestPosts } from './';
2+
import { IPost, IAuthor, IPostsState, IPostsJSON, postsReducer, receivePosts, requestPosts } from './';
33

4-
describe.only('posts-reducer', () => {
5-
// it('sets the initial state', () => expect(postsReducer(undefined, increaseCounter(1))).to.eql({ value: 1 }));
6-
// it('handles INCREASE_COUNTER', () => expect(postsReducer({ value: 10 }, increaseCounter(1))).to.eql({ value: 11 }));
7-
// it('handles DECREASE_COUNTER', () => expect(postsReducer({ value: 10 }, decreaseCounter(1))).to.eql({ value: 9 }));
4+
describe('posts / reducer', () => {
5+
it('handles REQUEST_POSTS', () =>
6+
expect(postsReducer(undefined, requestPosts())).to.eql({
7+
entities: {
8+
posts: {},
9+
authors: {},
10+
},
11+
result: [],
12+
isFetching: true,
13+
})
14+
);
15+
16+
it('handles RECEIVE_POSTS', () => {
17+
const author: IAuthor = {
18+
id: 'author1',
19+
name: 'Alex',
20+
email: 'alex@www.com',
21+
};
22+
23+
const post: IPost = {
24+
id: 'post1',
25+
title: 'Post title...',
26+
body: 'Post body...',
27+
author: author.id,
28+
};
29+
30+
const state: IPostsState = {
31+
entities: {
32+
posts: {},
33+
authors: {},
34+
},
35+
result: [],
36+
isFetching: true,
37+
};
38+
39+
const json: IPostsJSON = {
40+
data: [Object.assign({}, post, { author })],
41+
};
42+
43+
expect(postsReducer(state, receivePosts(json))).to.eql({
44+
isFetching: false,
45+
entities: {
46+
posts: {
47+
[post.id]: post,
48+
},
49+
authors: {
50+
[author.id]: author,
51+
},
52+
},
53+
result: [post.id],
54+
});
55+
});
856
});

src/store/posts/reducer.ts

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,40 @@
11
const { normalize, Schema, arrayOf } = require('normalizr');
2-
import { RECEIVE_POSTS, REQUEST_POSTS, IPostsState, IPostsAction } from './types';
3-
import { IPayloadAction, IReducerMap } from '../interfaces';
2+
import { RECEIVE_POSTS, REQUEST_POSTS, IPost, IPostsState, IPostsAction } from './types';
3+
import { INormalized } from '../interfaces';
44

55
const initialState: IPostsState = {
66
isFetching: false,
7-
entities: [],
7+
entities: {
8+
posts: {},
9+
authors: {},
10+
},
811
result: [],
912
};
1013

11-
const article = new Schema('articles');
12-
const user = new Schema('users');
13-
article.define({ author: user });
14-
15-
const REDUCERS: IReducerMap<IPostsState, IPostsAction> = {
16-
[RECEIVE_POSTS](state: IPostsState, action: IPostsAction): IPostsState {
17-
const { entities, result } = normalize(action.payload.data, arrayOf(article));
18-
return Object.assign({}, state, {
19-
entities,
20-
result,
21-
isFetching: false
22-
});
23-
},
14+
const post = new Schema('posts');
15+
const author = new Schema('authors');
2416

25-
[REQUEST_POSTS](state: IPostsState, action: IPostsAction): IPostsState {
26-
return Object.assign({}, state, { isFetching: true });
27-
},
28-
};
17+
post.define({ author });
18+
19+
function receivePosts(state: IPostsState, action: IPostsAction): IPostsState {
20+
const { entities, result } = <INormalized<IPost[], number[]>>normalize(action.payload.data, arrayOf(post));
21+
22+
return Object.assign({}, state, {
23+
entities,
24+
result,
25+
isFetching: false
26+
});
27+
}
28+
29+
function requestPosts(state: IPostsState, action: IPostsAction): IPostsState {
30+
return Object.assign({}, state, { isFetching: true });
31+
}
2932

3033
export function postsReducer(state: IPostsState = initialState, action: IPostsAction): IPostsState {
31-
const reducer = REDUCERS[action.type];
32-
return reducer ? reducer(state, action) : state;
34+
switch (action.type) {
35+
case RECEIVE_POSTS: return receivePosts(state, action);
36+
case REQUEST_POSTS: return requestPosts(state, action);
37+
}
38+
39+
return state;
3340
}

src/store/posts/types.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { IAction, IFetching, INormalized, IPayloadAction } from '../interfaces';
1+
import { IFetching, INormalized, IPayloadAction } from '../interfaces';
22

33
export interface IAuthor {
44
id: string;
@@ -13,11 +13,20 @@ export interface IPost {
1313
author: IAuthor | string;
1414
}
1515

16+
export interface IPostsMap {
17+
posts: {
18+
[id: string]: IPost;
19+
};
20+
authors: {
21+
[id: string]: IAuthor;
22+
};
23+
}
24+
1625
export interface IPostsJSON {
1726
data: IPost[];
1827
}
1928

20-
export interface IPostsState extends IFetching, INormalized<IPost[], number[]> { }
29+
export interface IPostsState extends IFetching, INormalized<IPostsMap, string[]> { }
2130

2231
export interface IPostsAction extends IPayloadAction<IPostsJSON> { }
2332

0 commit comments

Comments
 (0)