Skip to content

Commit 6aa9890

Browse files
author
Dennis Miasoutov
committed
Addin async redux flavor.
1 parent 0598618 commit 6aa9890

File tree

18 files changed

+222
-19
lines changed

18 files changed

+222
-19
lines changed

app/components/html.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export class Html extends React.Component<HtmlProps> {
3737
/>
3838
));
3939
const renderBottomInlineScripts = inlineScripts
40-
.filter(_ => _.position === "top")
40+
.filter(_ => _.position === "bottom")
4141
.map((inlineScript, i) => (
4242
<script
4343
key={i}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export * from "../router-redux/createContext";
2+
export * from "../router-redux/app";
3+
export * from "./render";
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import * as domain from "domain";
2+
import {
3+
baseUrl as domainTaskBaseUrl,
4+
run as domainTaskRun,
5+
} from "domain-task/main";
6+
import { createMemoryHistory } from "history";
7+
import * as React from "react";
8+
import { renderToStaticMarkup, renderToString } from "react-dom/server";
9+
import { Context, RenderCallback, RenderFuncProps } from "../../common";
10+
import { Html, HtmlProps } from "../../components";
11+
import { App } from "../router-redux/app";
12+
import { createContext } from "../router-redux/createContext";
13+
14+
export function render(callback: RenderCallback, props: RenderFuncProps): void {
15+
try {
16+
const history = createMemoryHistory();
17+
history.replace(props.requestUrl);
18+
const context: Context = createContext(history);
19+
context.helmetContext = {}; // init helmet for ssr
20+
const app = <App context={context} />;
21+
domainTaskRun(
22+
() => {
23+
renderToString(app);
24+
},
25+
/* completion callback */ errorOrNothing => {
26+
if (errorOrNothing) {
27+
callback(errorOrNothing);
28+
} else {
29+
const markup = renderToString(app);
30+
31+
const htmlProps: HtmlProps = {
32+
assets: props.assets,
33+
context,
34+
inlineScripts: props.inlineScripts,
35+
markup,
36+
};
37+
38+
const html = renderToStaticMarkup(<Html {...htmlProps} />);
39+
40+
callback(undefined, {
41+
html,
42+
});
43+
}
44+
},
45+
);
46+
} catch (error) {
47+
callback(error);
48+
}
49+
}

app/flavors/router-redux/createContext.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ import { Context } from "../../common";
99
import { middlewares, reducers } from "injected-app-module/store";
1010

1111
export function createContext(abstractHistory?: History): Context {
12-
const isSsr = typeof window === "undefined";
1312
const initialState =
14-
typeof isSsr || typeof (window as any).__PRELOADED_STATE__ === "undefined"
13+
typeof window === "undefined" ||
14+
typeof (window as any).__PRELOADED_STATE__ === "undefined"
1515
? undefined
1616
: JSON.parse((window as any)?.__PRELOADED_STATE__);
1717
const history = abstractHistory ?? createBrowserHistory();

app/wtb.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
{
22
"outputClientPath": "./wwwroot",
33
"outputServerPath": "./wwwroot_node",
4-
"enableRouterRedux": false,
5-
"serverSideRendering": true
4+
"flavor": "basic"
65
}

examples/redux/wtb.json

Lines changed: 0 additions & 3 deletions
This file was deleted.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import * as React from "react";
2+
import { Route, Switch } from "react-router-dom";
3+
import { StarsPage } from "./pages/stars";
4+
5+
export class App extends React.Component {
6+
public render(): JSX.Element {
7+
return (
8+
<Switch>
9+
<Route exact={true} path="/" component={StarsPage} />
10+
</Switch>
11+
);
12+
}
13+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import * as React from "react";
2+
import { Helmet } from "react-helmet-async";
3+
4+
import { connect } from "react-redux";
5+
import { fetchStarsAction } from "../store";
6+
7+
interface AppProps {
8+
stars?: number;
9+
}
10+
interface AppDispatch {
11+
loadData: () => void;
12+
}
13+
14+
class StarsPageInternal extends React.Component<AppProps & AppDispatch> {
15+
/**
16+
*
17+
*/
18+
constructor(props: AppProps & AppDispatch) {
19+
super(props);
20+
21+
if (props.stars == null) {
22+
props.loadData();
23+
}
24+
}
25+
public render(): JSX.Element {
26+
return (
27+
<div>
28+
<Helmet>
29+
<title>Fetching Stars Example</title>
30+
</Helmet>
31+
Stars: {this.props.stars ? this.props.stars : "loading..."}
32+
</div>
33+
);
34+
}
35+
}
36+
37+
const StarsPage = connect<AppProps, AppDispatch, {}, any>(
38+
state => ({
39+
stars: state.stars,
40+
}),
41+
dispatch => ({
42+
loadData: () => dispatch(fetchStarsAction() as any),
43+
}),
44+
)(StarsPageInternal);
45+
46+
export { StarsPage };
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { RouterState } from "connected-react-router";
2+
import { addTask } from "domain-task";
3+
import fetch = require("isomorphic-fetch");
4+
import * as Redux from "redux";
5+
import thunk from "redux-thunk";
6+
7+
interface ApplicationState {
8+
router?: RouterState;
9+
stars?: number;
10+
}
11+
12+
interface StatsAction extends Redux.Action<string> {
13+
stats?: number;
14+
}
15+
16+
const starsReducer = (
17+
state: number | null = null,
18+
action: StatsAction,
19+
): any => {
20+
switch (action.type) {
21+
case "LOAD_STARS":
22+
return action.stats;
23+
default:
24+
return state;
25+
}
26+
};
27+
28+
export function fetchStarsAction() {
29+
return (dispatch: Redux.Dispatch) => {
30+
const url =
31+
"https://api.github.com/repos/mocoding-software/webpack-typescript-builder";
32+
// Promise is added because there is a setTimeout
33+
const task = new Promise((resolve, reject) =>
34+
fetch(url)
35+
.then(response => response.json())
36+
.then(data =>
37+
setTimeout(() => {
38+
dispatch({
39+
stars: data.stargazers_count,
40+
type: "LOAD_STARS",
41+
}),
42+
resolve();
43+
}, 2000),
44+
),
45+
);
46+
addTask(task); // inform domain to wait until this is finished
47+
};
48+
}
49+
50+
const middlewares: Redux.Middleware[] = [thunk];
51+
const reducers: Redux.ReducersMapObject<ApplicationState> = {
52+
stars: starsReducer,
53+
};
54+
55+
export { middlewares, reducers };
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"flavor": "router-redux-async"
3+
}

0 commit comments

Comments
 (0)