Async-react-router is react router that can easily get initial props using async/await or promise.
If you use this library, You can get the initial props like Next.js.
And this library works only on client also.
Version | React | RxJS | README |
---|---|---|---|
2.0 | 15.X or 16.X | 6.X | Link |
1.0 | 15.X or 16.X | 5.X | Link |
In order to correspond to dynamic import, v2 has breaking change from v1.
- Support
getInitialProps()
like Next.js. - Support only on client-side.
- Support sever-side rendering.
- Support URL parameters.
- Support history package. The following history type is supported.
- Hash history
- Browser history
- Memory history
- Support dynamic import.
- No depend on react-router.
- Basic Example.
- Redux Example.
- Flux Utils Example.
- Server-side rendering (only example source)
Async-react-router has peer dependencies of rxjs@6.x.x which will have to be installed.
npm install async-react-router react react-dom rxjs --save
import React from 'react';
import { render } from "react-dom";
import { createRouter } from "async-react-router";
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
class Home extends React.Component {
static initialPropsWillGet(attributes, prevAttributes) {
console.log('Taking a break...');
}
static async getInitialProps(attributes, prevAttributes) {
await sleep(5000);
return {
message: 'Home is five second sleep.'
};
}
static initialPropsDidGet(props, prevProps) {
console.log('Five second later');
}
render() {
return (
<div>
<h2>Home</h2>
<dl>
<dt>Message</dt>
<dd>{this.props.message}</dd>
</dl>
<ul>
<li><Link to="/page">Page Index</Link></li>
<li><Link to="/page/1">Page 1</Link></li>
</ul>
</div>
);
};
}
const router = createRouter();
router.route("/", Home);
router.run((Root) => {
render(<Root/>, document.getElementById("app"));
});
createRouter()
generates router instance. Default history type is Hash history.
import { createRouter } from "async-react-router";
const router = createRouter();
If you want to change history type to browser history or memory history, you can define below.
// Browser history
import { createRouter, createBrowserHistory } from "async-react-router";
const router = createRouter(createBrowserHistory());
// Memory history
import { createRouter, createMemoryHistory } from "async-react-router";
const router = createRouter(createMemoryHistory());
Route links a path and a component.
path
- Any valid URL path that path-to-regexp understands. Required.component
- A react component to render only when the location matches. Required.name
- Route name. You can use atRequest.name(name)
, orURL.name(name)
. Optional.
import React from 'react';
import { createRouter } from 'async-react-router';
import Home from "./components/Home";
const router = createRouter();
router.route("/", Home, "Home");
router.run((Root) => {
render(<Root/>, document.getElementById("app"));
});
If you want to use dynamic import, You can define using asyncRoute()
.
path
- Any valid URL path that path-to-regexp understands. Required.component
- A react component to render only when the location matches. Required.name
- Route name. You can useRequest.name(name)
, orURL.name(name)
. Optional.
import { createRouter } from 'async-react-router';
const router = createRouter();
router.asyncRoute("/", () => import("./components/Home"), "Home");
router.run((Root) => {
hydrate(<Root />, document.getElementById("app"));
});
run
generates the root component.
import { createRouter } from 'async-react-router';
import Home from "./components/Home";
const router = createRouter();
router.route("/", Home, "Home");
router.run((Root) => {
render(<Root />, document.getElementById("app"));
});
If you want to add parameters, you can define parameters with the root component parameters.
import { createRouter } from 'async-react-router';
import Home from "./components/Home";
const router = createRouter();
router.route("/", Home, "Home");
router.run((Root) => {
render(<Root any={"any"}/>, document.getElementById("app"));
});
If you want to render any component at first rendering, you can define component.
import { createRouter } from 'async-react-router';
function FirstComponent() {
return (
<div className="text-center" style={{margin: "100px 0"}}>
<i className="fa fa-cog fa-spin fa-5x fa-fw"/>
</div>
)
}
const router = createRouter();
// Set first rendered component.
router.setFirstComponent(FirstComponent);
router.run((Root) => {
hydrate(<Root />, document.getElementById("app"));
});
If you want to render server-side, you will want to give initial data.
In that case, you can set initial data with setInitialProps()
.
When you use setInitialProps()
, initialPropsWillGet()
and initialPropsDidGet()
are not called for the first time.
Only getInitialProps()
is called.
import { createRouter } from 'async-react-router';
const router = createRouter();
// Set data from server.
router.setInitialProps(
JSON.parse(document.getElementById("initial-props").innerText);
);
router.run((Root) => {
hydrate(<Root/>, document.getElementById("app"));
});
<Link>
makes a request event and renders component matching route path.
import { Link } from 'async-react-router';
<Link to="/">Home</Link>
Route component can have initialPropsWillGet()
.
initialPropsWillGet()
is invoked immediately before mounting occurs. It is called before getInitialProps()
This method is static.
initialPropsWillGet()
has arguments below.
attributes
- Current route attributes.pathname
- String of the current path.params
- Object with the parsed url parameter. Defaults to {}.
prevAttributes
- Previous route attributes. Defaults to {}.pathname
- String of the previous path.params
- Object with the parsed url parameter at previous page. Defaults to {}.
async/await is not supported.
Route component can have getInitialProps()
that can use async/await.
getInitialProps()
perform the rendering after promise has been resolved, The resolved data can be retrieved as props of component.
This method is static.
And getInitialProps()
has arguments below.
attributes
- Current route attributes.pathname
- String of the current path.params
- Object with the parsed url parameter. Defaults to {}.
prevAttributes
- Previous route attributes. Defaults to {}.pathname
- String of the previous path.params
- Object with the parsed url parameter at previous page. Defaults to {}.
import { createRouter } from 'async-react-router';
class User extends React.Component {
static async getInitialProps(attributes, prevAttributes) {
console.log(attributes.params.userId);
return {
data: "Get initial props!!"
};
}
render() {
return (
<div>
<div>UserId: {this.props.params.userId}</div>
<div>Data: {this.props.data}</div>
</div>
);
}
}
const router = createrRouter();
router.route("/user/:userId", User);
router.run((Root) => {
render(<Root/>, document.getElementById("app"));
});
Route component can have initialPropsDidGet()
.
initialPropsDidGet()
is called after getInitialProps()
.
If more than one promise is pending, Async-react-router gets only data of last executed promise.
For this reason, initialPropsDidGet()
is executed only when the last promise is resolved.
This method is static.
initialPropsDidGet()
has arguments.
props
- Current props of components defined at route.pathname
- String of the current path.params
- Object with the parsed url parameter. Defaults to {}.{data}
- Data retrieved usinggetInitialProps()
.
prevProps
- Previous props of components defined at route. First rendering to {}.pathname
- String of the previous path.params
- Object with the parsed url parameter at previous page. Defaults to {}.{data}
- Data retrieved usinggetInitialProps()
.
async/await is not supported.
When you want to push next request, you can use to
of Request
.
path
- String of next path.
import { Request } from 'async-react-router';
Request.to('/next'); // Change url to `#/next`.
You can make next request from the name
defined at route.
routeName
- Route name for next request.urlParameters
- Object of next url parameters. Optional.
import React from 'react';
import { render } from 'react-dom';
import { createRouter, Request } from 'async-react-router';
class User extends React.Component {
render() { return (<div>{this.props.params.userId}</div>); };
}
const router = createRouter();
router.route("/user/:userId", User, "User");
router.run((Root) => {
render(<Root/>, document.getElementById("app"));
});
Request.name("User", {userId: 1}); // Change url to `#/user/1`.
When you want to check path, you can use isActive()
of Request
.
import { Request } from 'async-react-router';
// When current path is `/`...
Request.isActive('/'); // true
Request.isActive('/path'); // false
When you want to make path, you can use to
of URL
.
path
- String of path.
import { URL } from 'async-react-router';
URL.to('/next'); // String `#/next`.
You can make URL from the name
defined at route.
routeName
- Route name.urlParameters
- Object of url parameter, if it requires.
import React from 'react';
import { render } from 'react-dom';
import { createRouter, URL } from 'async-react-router';
class User extends React.Component {
render() { return (<div>{this.props.params.userId}</div>); };
}
const router = createRouter();
router.route("/user/:userId", User, "User");
router.run((Root) => {
render(<Root/>, document.getElementById("app"));
});
URL.name("User", {userId: 1}); // String `#/user/1`.
Async-react-router supports server-side rendering.
SSR.createServerRouter()
generates server-side router instance.- You can deal with SSR just by changing
createRouter()
toSSR.createRouter()
on client side. - It is also possible to obtain resolved data on the server side via HTML on client-side.
SSR.createServerRouter()
generates server-side router instance. Supported history type is only memory history.
serverRouter
instance has route()
and asyncRoute()
also.
import { SSR } from "async-react-router";
app.get("*", function(req, res) {
function setRoutes(router) {
router.route("/", IndexPage);
router.asyncRoute("/user", () => import("./UserPage"));
}
const serverRouter = SSR.createServerRouter();
setRoutes(serverRouter);
}
serverRouter.runUsingPathname()
generates root component and initial data.
getInitialProps()
and initialPropsWillGet()
, initialPropsDidGet()
are not called for the first time.
import ejs from "ejs";
import React from "react";
import ReactDOMServer from "react-dom/server";
import express from "express";
import { SSR } from "async-react-router";
import fs from "fs";
const app = express();
app.get("*", function(req, res) {
// Please make another file and import.
function setRoutes(router) {
router.route("/", IndexPage);
router.asyncRoute("/user", () => import("./UserPage"));
}
const serverRouter = SSR.createServerRouter();
setRoutes(serverRouter);
serverRouter.runUsingPathname(req.url, (Root, data) => {
fs.readFile("index.html", function(err, result) {
const compiled = ejs.compile(result.toString("utf8"), "utf8");
const html = compiled({
component: ReactDOMServer.renderToString(<Root/>),
data: data
});
res.write(html);
res.end();
});
});
}
SSR.createrRouter ()
generates a router instance with the same functionality as createrRouter ()
.
The only difference is history type.
Supported history type is only browser history.
Hash History and Memory History cannot be used.
import React from "react";
import { hydrate } from "react-dom";
import { SSR } from "async-react-router";
// Please make another file and import.
function setRoutes(router) {
router.route("/", IndexPage);
router.asyncRoute("/user", () => import("./UserPage"));
}
const router = SSR.createRouter();
setRoutes(router);
router.setInitialProps(JSON.parse(document.getElementById("initial-props").innerText));
router.run((Root) => {
hydrate(<Root/>, document.getElementById("app"));
});
This is the same process as below.
import React from "react";
import { hydrate } from "react-dom";
import { createRouter, createBrowserHistory } from "async-react-router";
// Please make another file and import.
function setRoutes(router) {
router.route("/", IndexPage);
router.asyncRoute("/user", () => import("./UserPage"));
}
const router = createRouter(createBrowserHistory());
setRoutes(router);
router.setInitialProps(JSON.parse(document.getElementById("initial-props").innerText));
router.run((Root) => {
hydrate(<Root/>, document.getElementById("app"));
});
MIT