All Projects → oneut → async-react-router

oneut / async-react-router

Licence: MIT license
Client side react router with async. It like next.js!

Programming Languages

javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to async-react-router

React 5ddm
5d动漫,使用React,服务端渲染,接口(不开源)来自赞片CMS。仅供参考,交流群:14646823 欢迎加入
Stars: ✭ 50 (+138.1%)
Mutual labels:  react-router, ssr
Preact Redux Isomorphic
preact-redux-isomorphic PWA SPA SSR best practices and libraries in under 80kB page size (for live demo click the link below)
Stars: ✭ 85 (+304.76%)
Mutual labels:  react-router, ssr
Piwik React Router
Piwik analytics component for react-router
Stars: ✭ 53 (+152.38%)
Mutual labels:  react-router, history
After.js
Next.js-like framework for server-rendered React apps built with React Router
Stars: ✭ 4,051 (+19190.48%)
Mutual labels:  react-router, ssr
Nostalgie
Nostalgie is an opinionated, full-stack, runtime-agnostic framework for building web apps and web pages using react.
Stars: ✭ 130 (+519.05%)
Mutual labels:  react-router, ssr
React Router Server
Server Side Rendering library for React Router v4.
Stars: ✭ 443 (+2009.52%)
Mutual labels:  react-router, ssr
React Router Nextjs Like Data Fetching
Demonstrating React Router 4's SSR awesomeness
Stars: ✭ 84 (+300%)
Mutual labels:  react-router, ssr
react-ssr
从零搭建一个react-ssr框架 解决页面js事件 样式同构 服务器客户端路由 数据注水脱水等问题
Stars: ✭ 42 (+100%)
Mutual labels:  react-router, ssr
Reeakt
A modern React boilerplate to awesome web applications
Stars: ✭ 116 (+452.38%)
Mutual labels:  react-router, ssr
Award
⚙基于react的服务端渲染框架
Stars: ✭ 91 (+333.33%)
Mutual labels:  react-router, ssr
React Lego
React-lego : incrementally add more cool stuff to your react app
Stars: ✭ 417 (+1885.71%)
Mutual labels:  react-router, ssr
Accounts Ui
Accounts UI for React in Meteor 1.3+
Stars: ✭ 197 (+838.1%)
Mutual labels:  react-router, ssr
Ice
🚀 The Progressive App Framework Based On React(基于 React 的渐进式应用框架)
Stars: ✭ 16,961 (+80666.67%)
Mutual labels:  react-router, ssr
Loadable Components
The recommended Code Splitting library for React ✂️✨
Stars: ✭ 6,194 (+29395.24%)
Mutual labels:  react-router, ssr
react16-seed-with-apollo-graphql-scss-router4-ssr-tests-eslint-prettier-docker-webpack3-hot
Seed to create your own project using React with Apollo GraphQL client
Stars: ✭ 19 (-9.52%)
Mutual labels:  react-router, ssr
Dva Starter
完美使用 dva react react-router,最好用的ssr脚手架,服务器渲染最佳实践
Stars: ✭ 60 (+185.71%)
Mutual labels:  react-router, ssr
elegant-react-ssr
Server-side rendering with create-react-app, React Router v4, Helmet, Redux, and Thunk boilerplate, without ejecting CRA
Stars: ✭ 16 (-23.81%)
Mutual labels:  react-router, ssr
React Redux Saucepan
A minimal and universal react redux starter project. With hot reloading, linting and server-side rendering
Stars: ✭ 86 (+309.52%)
Mutual labels:  react-router, ssr
Redux First History
🎉 Redux First History - Redux history binding support react-router - @reach/router - wouter
Stars: ✭ 163 (+676.19%)
Mutual labels:  react-router, history
React Router Last Location
Provides access to the last location in react + react-router (v4.x, v5.x) applications. ❤️ Using hooks? useLastLocation | 💉 Using HOC? withLastLocation
Stars: ✭ 251 (+1095.24%)
Mutual labels:  react-router, history

async-react-router

Build Status npm version Coverage Status dependencies Status Commitizen friendly

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

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.

Features

  • 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.

Demo

Installation

Async-react-router has peer dependencies of [email protected] which will have to be installed.

npm install async-react-router react react-dom rxjs --save

Example

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"));
});

API

createRouter()

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());

router.route(path, component, name)

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 at Request.name(name), or URL.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"));
});

router.asyncRoute(path, () => promise, name)

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 use Request.name(name), or URL.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"));
});

router.run((RootComponent) => void)

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"));
});

router.setFirstComponent(component)

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"));
});

router.setInitialProps(parameters)

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

<Link> makes a request event and renders component matching route path.

import { Link } from 'async-react-router';

<Link to="/">Home</Link>

Route component

component.initialPropsWillGet(attributes, prevAttributes): void

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.

component.getInitialProps(attributes, prevAttributes): Object

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"));
});

component.initialPropsDidGet(props, prevProps): void

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 using getInitialProps().
  • 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 using getInitialProps().

async/await is not supported.

Request

Request.to(path)

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`.

Request.name(routeName, urlParameters)

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`.

Request.isActive(path)

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

URL

URL.to(path)

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`.

URL.name(routeName, urlParameters)

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`.

Server Side Rendering

Async-react-router supports server-side rendering.

  • SSR.createServerRouter() generates server-side router instance.
  • You can deal with SSR just by changing createRouter() to SSR.createRouter() on client side.
  • It is also possible to obtain resolved data on the server side via HTML on client-side.

Server Side

SSR.createServerRouter()

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(pathname, callback(RootComponent, data) => void)

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();
        });
  });
}

Client Side

SSR.createRouter()

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"));
});

Thanks for the inspiration

License

MIT

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].