{"id":18188529,"url":"https://github.com/oneut/async-react-router","last_synced_at":"2025-06-21T09:34:02.536Z","repository":{"id":57185767,"uuid":"91824874","full_name":"oneut/async-react-router","owner":"oneut","description":"Client side react router with async. It like next.js!","archived":false,"fork":false,"pushed_at":"2018-10-14T04:25:14.000Z","size":16989,"stargazers_count":21,"open_issues_count":0,"forks_count":3,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-06-06T21:42:28.083Z","etag":null,"topics":["async","history","nextjs","react","react-router","ssr"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/oneut.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-05-19T16:24:12.000Z","updated_at":"2023-03-22T19:17:45.000Z","dependencies_parsed_at":"2022-09-06T04:02:11.116Z","dependency_job_id":null,"html_url":"https://github.com/oneut/async-react-router","commit_stats":null,"previous_names":[],"tags_count":34,"template":false,"template_full_name":null,"purl":"pkg:github/oneut/async-react-router","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oneut%2Fasync-react-router","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oneut%2Fasync-react-router/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oneut%2Fasync-react-router/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oneut%2Fasync-react-router/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/oneut","download_url":"https://codeload.github.com/oneut/async-react-router/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oneut%2Fasync-react-router/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260438832,"owners_count":23009267,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["async","history","nextjs","react","react-router","ssr"],"created_at":"2024-11-03T03:03:18.757Z","updated_at":"2025-06-21T09:33:57.524Z","avatar_url":"https://github.com/oneut.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# async-react-router\n\n[![Build Status](https://travis-ci.org/oneut/async-react-router.svg?branch=master)](https://travis-ci.org/oneut/async-react-router)\n[![npm version](https://img.shields.io/npm/v/async-react-router.svg?style=flat)](https://www.npmjs.com/package/async-react-router) \n[![Coverage Status](https://coveralls.io/repos/github/oneut/async-react-router/badge.svg?branch=master)](https://coveralls.io/github/oneut/async-react-router?branch=master)\n[![dependencies Status](https://david-dm.org/oneut/async-react-router/status.svg)](https://david-dm.org/oneut/async-react-router)\n[![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/)\n\nAsync-react-router is react router that can easily get initial props using async/await or promise.  \nIf you use this library, You can get the initial props like Next.js.   \nAnd this library works only on client also.\n\n## Version\n\n|Version|React|RxJS|README|\n|:---:|:---:|:---:|:---:|\n|2.0|15.X or 16.X|6.X|[Link](https://github.com/oneut/async-react-router/tree/master)|\n|1.0|15.X or 16.X|5.X|[Link](https://github.com/oneut/async-react-router/tree/1.0-stable)|\n\nIn order to correspond to dynamic import, v2 has breaking change from v1.\n\n## Features\n+ Support `getInitialProps()` like Next.js.\n+ Support only on client-side.\n+ Support sever-side rendering.\n+ Support URL parameters.\n+ Support [history](https://www.npmjs.com/package/history) package. The following history type is supported.\n    + Hash history\n    + Browser history\n    + Memory history\n+ Support dynamic import.\n+ No depend on react-router.\n\n## Demo\n+ [Basic Example.](https://oneut.github.io/async-react-router/basic/)\n+ [Redux Example.](https://oneut.github.io/async-react-router/redux/)\n+ [Flux Utils Example.](https://oneut.github.io/async-react-router/flux-utils/)\n+ Server-side rendering (only [example source](https://github.com/oneut/async-react-router/tree/master/examples/ssr-with-redux))\n\n## Installation\n\nAsync-react-router has peer dependencies of [rxjs@6.x.x](https://github.com/Reactive-Extensions/RxJS) which will have to be installed.\n\n```\nnpm install async-react-router react react-dom rxjs --save\n```\n\n## Example\n```javascript\nimport React from 'react';\nimport { render } from \"react-dom\";\nimport { createRouter } from \"async-react-router\";\n\nfunction sleep(ms) {\n    return new Promise((resolve) =\u003e setTimeout(resolve, ms));\n}\n\nclass Home extends React.Component {\n    static initialPropsWillGet(attributes, prevAttributes) {\n        console.log('Taking a break...');\n    }\n    \n    static async getInitialProps(attributes, prevAttributes) {\n        await sleep(5000);\n        return {\n            message: 'Home is five second sleep.'\n        };\n    }\n    \n    static initialPropsDidGet(props, prevProps) {\n        console.log('Five second later');\n    }\n\n    render() {\n        return (\n            \u003cdiv\u003e\n                \u003ch2\u003eHome\u003c/h2\u003e\n                \u003cdl\u003e\n                    \u003cdt\u003eMessage\u003c/dt\u003e\n                    \u003cdd\u003e{this.props.message}\u003c/dd\u003e\n                \u003c/dl\u003e\n                \u003cul\u003e\n                    \u003cli\u003e\u003cLink to=\"/page\"\u003ePage Index\u003c/Link\u003e\u003c/li\u003e\n                    \u003cli\u003e\u003cLink to=\"/page/1\"\u003ePage 1\u003c/Link\u003e\u003c/li\u003e\n                \u003c/ul\u003e\n            \u003c/div\u003e\n        );\n    };\n}\n\nconst router = createRouter();\nrouter.route(\"/\", Home);\nrouter.run((Root) =\u003e {\n  render(\u003cRoot/\u003e, document.getElementById(\"app\"));\n});\n```\n\n# API\n## createRouter()\n\n`createRouter()` generates router instance. Default history type is **Hash history**. \n\n```javascript\nimport { createRouter } from \"async-react-router\";\n\nconst router = createRouter();\n```\n\nIf you want to change history type to browser history or memory history, you can define below.\n\n```javascript\n// Browser history\nimport { createRouter, createBrowserHistory } from \"async-react-router\";\nconst router = createRouter(createBrowserHistory());\n\n// Memory history\nimport { createRouter, createMemoryHistory } from \"async-react-router\";\nconst router = createRouter(createMemoryHistory());\n```\n\n### router.route(path, component, name)\n\nRoute links a path and a component.\n\n+ `path` - Any valid URL path that [path-to-regexp](https://github.com/pillarjs/path-to-regexp) understands. Required.\n+ `component` - A react component to render only when the location matches. Required.\n+ `name` - Route name. You can use at `Request.name(name)`, or `URL.name(name)`. Optional.\n\n```javascript\nimport React from 'react';\nimport { createRouter } from 'async-react-router';\nimport Home from \"./components/Home\";\n\nconst router = createRouter();\nrouter.route(\"/\", Home, \"Home\");\nrouter.run((Root) =\u003e {\n  render(\u003cRoot/\u003e, document.getElementById(\"app\"));\n});\n```\n\n### router.asyncRoute(path, () =\u003e promise, name)\n\nIf you want to use dynamic import, You can define using `asyncRoute()`. \n\n+ `path` - Any valid URL path that [path-to-regexp](https://github.com/pillarjs/path-to-regexp) understands. Required.\n+ `component` - A react component to render only when the location matches. Required.\n+ `name` - Route name. You can use `Request.name(name)`, or `URL.name(name)`. Optional.\n\n```javascript\nimport { createRouter } from 'async-react-router';\n\nconst router = createRouter();\nrouter.asyncRoute(\"/\", () =\u003e import(\"./components/Home\"), \"Home\");\nrouter.run((Root) =\u003e {\n  hydrate(\u003cRoot /\u003e, document.getElementById(\"app\"));\n});\n```\n\n### router.run((RootComponent) =\u003e void)\n\n`run` generates the root component.\n\n```javascript\nimport { createRouter } from 'async-react-router';\nimport Home from \"./components/Home\";\n\nconst router = createRouter();\nrouter.route(\"/\", Home, \"Home\");\nrouter.run((Root) =\u003e {\n  render(\u003cRoot /\u003e, document.getElementById(\"app\"));\n});\n```\n\nIf you want to add parameters, you can define parameters with the root component parameters.\n\n```javascript\nimport { createRouter } from 'async-react-router';\nimport Home from \"./components/Home\";\n\nconst router = createRouter();\nrouter.route(\"/\", Home, \"Home\");\nrouter.run((Root) =\u003e {\n  render(\u003cRoot any={\"any\"}/\u003e, document.getElementById(\"app\"));\n});\n```\n\n### router.setFirstComponent(component)\n\nIf you want to render any component at first rendering, you can define component.\n\n```javascript\nimport { createRouter } from 'async-react-router';\nfunction FirstComponent() {\n  return (\n    \u003cdiv className=\"text-center\" style={{margin: \"100px 0\"}}\u003e\n      \u003ci className=\"fa fa-cog fa-spin fa-5x fa-fw\"/\u003e\n    \u003c/div\u003e\n  )\n}\n\nconst router = createRouter();\n\n// Set first rendered component.\nrouter.setFirstComponent(FirstComponent);\n\nrouter.run((Root) =\u003e {\n  hydrate(\u003cRoot /\u003e, document.getElementById(\"app\"));\n});\n```\n\n### router.setInitialProps(parameters)\n\nIf you want to render server-side, you will want to give initial data. \nIn that case, you can set initial data with `setInitialProps()`.  \nWhen you use `setInitialProps()`, `initialPropsWillGet()` and `initialPropsDidGet()` are not called for the first time.  \nOnly `getInitialProps()` is called.\n\n```javascript\nimport { createRouter } from 'async-react-router';\n\nconst router = createRouter();\n\n// Set data from server.\nrouter.setInitialProps(\n  JSON.parse(document.getElementById(\"initial-props\").innerText);\n);\n\nrouter.run((Root) =\u003e {\n  hydrate(\u003cRoot/\u003e, document.getElementById(\"app\"));\n});\n```\n\n## Link\n\n`\u003cLink\u003e` makes a request event and renders component matching route path.\n\n```javascript\nimport { Link } from 'async-react-router';\n\n\u003cLink to=\"/\"\u003eHome\u003c/Link\u003e\n```\n\n## Route component\n### `component.initialPropsWillGet(attributes, prevAttributes): void`\n\nRoute component can have `initialPropsWillGet()`.  \n`initialPropsWillGet()` is invoked immediately before mounting occurs. It is called before `getInitialProps()`\nThis method is static.\n\n`initialPropsWillGet()` has arguments below.\n\n+ `attributes` - Current route attributes. \n    + `pathname` - String of the current path.\n    + `params` - Object with the parsed url parameter. Defaults to {}.\n+ `prevAttributes` - Previous route attributes. Defaults to {}.\n    + `pathname` - String of the previous path.\n    + `params` - Object with the parsed url parameter at previous page. Defaults to {}.\n\n**async/await is not supported.**\n\n\n### `component.getInitialProps(attributes, prevAttributes): Object`\n\nRoute component can have `getInitialProps()` that can use async/await.  \n`getInitialProps()` perform the rendering after promise has been resolved, The resolved data can be retrieved as props of component.\nThis method is static.\n\nAnd `getInitialProps()` has arguments below.\n\n+ `attributes` - Current route attributes. \n    + `pathname` - String of the current path.\n    + `params` - Object with the parsed url parameter. Defaults to {}.\n+ `prevAttributes` - Previous route attributes. Defaults to {}.\n    + `pathname` - String of the previous path.\n    + `params` - Object with the parsed url parameter at previous page. Defaults to {}.\n\n```javascript\nimport { createRouter } from 'async-react-router';\n\nclass User extends React.Component {\n    static async getInitialProps(attributes, prevAttributes) {\n        console.log(attributes.params.userId);\n        return { \n          data: \"Get initial props!!\" \n        };\n    }\n    \n    render() {\n        return (\n            \u003cdiv\u003e\n                \u003cdiv\u003eUserId: {this.props.params.userId}\u003c/div\u003e\n                \u003cdiv\u003eData: {this.props.data}\u003c/div\u003e\n            \u003c/div\u003e\n        );\n    }\n}\n\nconst router = createrRouter();\nrouter.route(\"/user/:userId\", User);\nrouter.run((Root) =\u003e {\n  render(\u003cRoot/\u003e, document.getElementById(\"app\"));\n});\n```\n\n\n### `component.initialPropsDidGet(props, prevProps): void`\n\nRoute component can have `initialPropsDidGet()`.  \n`initialPropsDidGet()` is called after `getInitialProps()`.  \nIf more than one promise is pending, Async-react-router gets only data of last executed promise.  \nFor this reason, `initialPropsDidGet()` is executed only when the last promise is resolved.\nThis method is static.\n\n`initialPropsDidGet()` has arguments.\n\n+ `props` - Current props of components defined at route. \n    + `pathname` - String of the current path.\n    + `params` - Object with the parsed url parameter. Defaults to {}.\n    + `{data}` - Data retrieved using `getInitialProps()`. \n+ `prevProps` - Previous props of components defined at route. First rendering to {}.\n    + `pathname` - String of the previous path.\n    + `params` - Object with the parsed url parameter at previous page. Defaults to {}.\n    + `{data}` - Data retrieved using `getInitialProps()`. \n    \n**async/await is not supported.**\n\n## Request\n### `Request.to(path)`\n\nWhen you want to push next request, you can use `to` of `Request`.\n\n+ `path` - String of next path.\n\n```javascript\nimport { Request } from 'async-react-router';\n\nRequest.to('/next'); // Change url to `#/next`.\n```\n\n\n### `Request.name(routeName, urlParameters)`\n\nYou can make next request from the `name` defined at route.\n\n+ `routeName` - Route name for next request.\n+ `urlParameters` - Object of next url parameters. Optional.\n\n```javascript\nimport React from 'react';\nimport { render } from 'react-dom';\nimport { createRouter, Request } from 'async-react-router';\n\nclass User extends React.Component {\n    render() { return (\u003cdiv\u003e{this.props.params.userId}\u003c/div\u003e); };\n}\n\nconst router = createRouter();\nrouter.route(\"/user/:userId\", User, \"User\");\nrouter.run((Root) =\u003e {\n  render(\u003cRoot/\u003e, document.getElementById(\"app\"));\n});\n\nRequest.name(\"User\", {userId: 1}); // Change url to `#/user/1`.\n```\n\n### `Request.isActive(path)`\n\nWhen you want to check path, you can use `isActive()` of `Request`.\n\n```javascript\nimport { Request } from 'async-react-router';\n\n// When current path is `/`...\nRequest.isActive('/');     // true\nRequest.isActive('/path'); // false\n```\n\n\n## URL\n### `URL.to(path)`\n\nWhen you want to make path, you can use `to` of `URL`.\n\n+ `path` - String of path.\n\n```javascript\nimport { URL } from 'async-react-router';\n\nURL.to('/next'); // String `#/next`.\n```\n\n### `URL.name(routeName, urlParameters)`\n\nYou can make URL from the `name` defined at route.\n\n+ `routeName` - Route name.\n+ `urlParameters` - Object of url parameter, if it requires.\n\n```javascript\nimport React from 'react';\nimport { render } from 'react-dom';\nimport { createRouter, URL } from 'async-react-router';\n\nclass User extends React.Component {\n    render() { return (\u003cdiv\u003e{this.props.params.userId}\u003c/div\u003e); };\n}\n\nconst router = createRouter();\nrouter.route(\"/user/:userId\", User, \"User\");\nrouter.run((Root) =\u003e {\n  render(\u003cRoot/\u003e, document.getElementById(\"app\"));\n});\n\nURL.name(\"User\", {userId: 1}); // String `#/user/1`.\n```\n\n# Server Side Rendering\n\nAsync-react-router supports server-side rendering.\n\n+ `SSR.createServerRouter()` generates server-side router instance.\n+ You can deal with SSR just by changing `createRouter()` to `SSR.createRouter()` on client side.\n+ It is also possible to obtain resolved data on the server side via HTML on client-side.\n\n## Server Side\n### `SSR.createServerRouter()`\n\n`SSR.createServerRouter()` generates server-side router instance. Supported history type is only **memory history**. \n`serverRouter` instance has `route()` and `asyncRoute()` also.\n\n```javascript\nimport { SSR } from \"async-react-router\";\n\napp.get(\"*\", function(req, res) {\n  function setRoutes(router) {\n    router.route(\"/\", IndexPage);\n    router.asyncRoute(\"/user\", () =\u003e import(\"./UserPage\"));\n  }\n  \n  const serverRouter = SSR.createServerRouter();\n  setRoutes(serverRouter);\n}\n```\n\n\n### serverRouter.runUsingPathname(pathname, callback(RootComponent, data) =\u003e void)\n\n`serverRouter.runUsingPathname()` generates root component and initial data.  \n`getInitialProps()` and `initialPropsWillGet()`, `initialPropsDidGet()` are not called for the first time.\n\n```javascript\nimport ejs from \"ejs\";\nimport React from \"react\";\nimport ReactDOMServer from \"react-dom/server\";\nimport express from \"express\";\nimport { SSR } from \"async-react-router\";\nimport fs from \"fs\";\n\nconst app = express();\n\napp.get(\"*\", function(req, res) {\n  // Please make another file and import.\n  function setRoutes(router) {\n    router.route(\"/\", IndexPage);\n    router.asyncRoute(\"/user\", () =\u003e import(\"./UserPage\"));\n  }\n  \n  const serverRouter = SSR.createServerRouter();\n  setRoutes(serverRouter);\n  serverRouter.runUsingPathname(req.url, (Root, data) =\u003e {\n    fs.readFile(\"index.html\", function(err, result) {\n          const compiled = ejs.compile(result.toString(\"utf8\"), \"utf8\");\n          const html = compiled({\n            component: ReactDOMServer.renderToString(\u003cRoot/\u003e),\n            data: data\n          });\n    \n          res.write(html);\n          res.end();\n        });\n  });\n}\n```\n\n## Client Side\n### `SSR.createRouter()`\n\n`SSR.createrRouter ()` generates a router instance with the same functionality as `createrRouter ()`.\nThe only difference is history type.  \nSupported history type is only **browser history**.\n**Hash History** and **Memory History** cannot be used.\n\n```javascript\nimport React from \"react\";\nimport { hydrate } from \"react-dom\";\nimport { SSR } from \"async-react-router\";\n\n// Please make another file and import.\nfunction setRoutes(router) {\n    router.route(\"/\", IndexPage);\n    router.asyncRoute(\"/user\", () =\u003e import(\"./UserPage\"));\n}\n\nconst router = SSR.createRouter();\nsetRoutes(router);\nrouter.setInitialProps(JSON.parse(document.getElementById(\"initial-props\").innerText));\nrouter.run((Root) =\u003e {\n  hydrate(\u003cRoot/\u003e, document.getElementById(\"app\"));\n});\n```\n\nThis is the same process as below.\n\n```javascript\nimport React from \"react\";\nimport { hydrate } from \"react-dom\";\nimport { createRouter, createBrowserHistory } from \"async-react-router\";\n\n// Please make another file and import.\nfunction setRoutes(router) {\n    router.route(\"/\", IndexPage);\n    router.asyncRoute(\"/user\", () =\u003e import(\"./UserPage\"));\n}\n\nconst router = createRouter(createBrowserHistory());\nsetRoutes(router);\nrouter.setInitialProps(JSON.parse(document.getElementById(\"initial-props\").innerText));\nrouter.run((Root) =\u003e {\n  hydrate(\u003cRoot/\u003e, document.getElementById(\"app\"));\n});\n```\n\n## Thanks for the inspiration\n+ [next.js](https://github.com/zeit/next.js/)\n+ [react-router](https://github.com/ReactTraining/react-router)\n+ [react-enroute](https://github.com/tj/react-enroute)\n+ [enroute](https://github.com/lapwinglabs/enroute)\n+ [path-to-regex](https://github.com/pillarjs/path-to-regexp)\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foneut%2Fasync-react-router","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Foneut%2Fasync-react-router","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foneut%2Fasync-react-router/lists"}