Skip to content

Commit b11dbba

Browse files
committed
feat(redux-saga): ssr with redux-saga
1 parent 9741da8 commit b11dbba

7 files changed

Lines changed: 42 additions & 42 deletions

File tree

src/app/containers/Stars.test.tsx

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,32 @@
11
import {renderComponent} from "../helpers/TestHelper";
22
import {Stars} from "./Stars";
33

4-
/** Mock App. State */
5-
const state: object = {
6-
stars: {
7-
isFetching: false,
8-
payload: {
9-
stargazers_count: 61
10-
}
11-
}
12-
};
13-
14-
describe("<Counter />", () => {
15-
16-
const component = renderComponent(Stars, state);
17-
18-
it("Renders header", () => {
19-
expect(component.find("div")).toBeDefined();
20-
// expect(component.find("div")).toHaveText("61");
4+
describe("<Stars />", () => {
5+
6+
it("Renders stars", () => {
7+
const state: object = {
8+
stars: {
9+
payload: {
10+
stargazers_count: 61
11+
}
12+
}
13+
};
14+
15+
const component = renderComponent(Stars, state);
16+
17+
expect(component.find("div")).toHaveText("61");
18+
});
19+
20+
it("Renders fetching", () => {
21+
const state: object = {
22+
stars: {
23+
payload: null
24+
}
25+
};
26+
27+
const component = renderComponent(Stars, state);
28+
29+
expect(component.find("div")).toHaveText("Fetching Stars..");
2130
});
2231

2332
});

src/app/containers/Stars.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,16 @@ interface IProps {
1616
)
1717
class Stars extends React.Component<IProps, {}> {
1818
public componentWillMount(): void {
19-
this.props.getStars();
19+
if (!this.props.stars.payload) {
20+
this.props.getStars();
21+
}
2022
}
2123

2224
public render(): JSX.Element {
2325
const {stars} = this.props;
24-
2526
return (
2627
<div>
27-
{stars.isFetching ? "Fetching Stars" : stars.payload.stargazers_count}
28+
{stars.payload ? stars.payload.stargazers_count : "Fetching Stars.."}
2829
</div>
2930
);
3031
}

src/app/helpers/promiseReducer.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,17 @@ export default function promiseReducer<TState, TAction>(baseAction: string, stat
44
switch (action.type) {
55
case baseAction + "_REQUEST":
66
return Object.assign({}, state, {
7-
isFetching: true
7+
payload: null
88
});
99

1010
case baseAction + "_SUCCESS":
1111
return Object.assign({}, state, {
12-
isFetching: false,
1312
payload: action.payload
1413
});
1514

1615
case baseAction + "_FAILURE":
1716
return Object.assign({}, state, {
1817
error: true,
19-
isFetching: false,
2018
message: action.message
2119
});
2220

src/app/models/starsModel.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
export interface IStars {
2-
isFetching?: boolean;
32
error?: boolean;
43
message?: string;
54
payload?: {

src/app/redux/modules/starsModule.test.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ describe("Stars Reducer", () => {
55
it("handles action of type STARS_REQUEST", () => {
66
const action = { type: STARS_REQUEST };
77
const stateBefore = {};
8-
const stateAfter = { isFetching: true };
8+
const stateAfter = { payload: null };
99
expect(starsReducer(stateBefore, action)).toEqual(stateAfter);
1010
});
1111

@@ -18,7 +18,6 @@ describe("Stars Reducer", () => {
1818
};
1919
const stateBefore = {};
2020
const stateAfter = {
21-
isFetching: false,
2221
payload: {
2322
stargazers_count: 99
2423
}
@@ -29,14 +28,14 @@ describe("Stars Reducer", () => {
2928
it("handles action of type STARS_FAILURE", () => {
3029
const action = { type: STARS_FAILURE };
3130
const stateBefore = {};
32-
const stateAfter = { error: true, isFetching: false };
31+
const stateAfter = { error: true};
3332
expect(starsReducer(stateBefore, action)).toEqual(stateAfter);
3433
});
3534

3635
it("handles actions with unknown type", () => {
3736
const action = { type: "" };
38-
const stateBefore = { isFetching: false };
39-
const stateAfter = { isFetching: false };
37+
const stateBefore = { payload: null };
38+
const stateAfter = { payload: null };
4039
expect(starsReducer(stateBefore, action)).toEqual(stateAfter);
4140
});
4241

src/app/redux/modules/starsModule.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,7 @@ export const STARS_FAILURE: string = "stars/STARS_FAILURE";
88

99
/** Initial State */
1010
const initialState: IStars = {
11-
isFetching: false,
12-
payload: {
13-
stargazers_count: -1
14-
}
11+
payload: null
1512
};
1613

1714
/** Reducer */

src/server.tsx

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -60,20 +60,16 @@ app.get("*", (req, res) => {
6060
res.redirect(302, redirectLocation.pathname + redirectLocation.search);
6161
} else if (renderProps) {
6262
store.runSaga(rootSaga).done.then(() => {
63-
// store will be mutated during the second render (because of componentDidMount)
64-
// deep clone state
63+
// deep clone state because store will be mutated during the second render in componentWillMount
6564
const initialState = JSON.parse(JSON.stringify(store.getState()));
66-
console.info("before markup => store.stars = " + JSON.stringify(store.getState().stars));
65+
66+
// render again from the initial data
6767
const markup = renderToString(
6868
<Provider store={store} key="provider">
6969
<RouterContext {...renderProps} />
7070
</Provider>
7171
);
72-
console.info("after markup => store.stars = " + JSON.stringify(store.getState().stars));
73-
console.info("--------------------------------");
74-
console.info("--------------------------------");
75-
console.info("--------------------------------");
76-
console.info("markup = " + markup);
72+
7773
if (appConfig.ssr) {
7874
res.status(200).send(renderHTML(markup, initialState));
7975
} else {
@@ -88,12 +84,13 @@ app.get("*", (req, res) => {
8884
res.status(500).send(err.message);
8985
});
9086

91-
console.info("before renderToString => state.stars = " + JSON.stringify(store.getState().stars));
87+
// first render to activate componentWillMount to dispatch actions for loading initial data
9288
renderToString(
9389
<Provider store={store} key="provider">
9490
<RouterContext {...renderProps} />
9591
</Provider>
9692
);
93+
// dispatching END will cause the root saga to terminate after all fired tasks terminate
9794
store.close();
9895
} else {
9996
res.status(404).send("Not Found?");

0 commit comments

Comments
 (0)