Skip to content

Latest commit

 

History

History
137 lines (113 loc) · 4.29 KB

how-to-implement-routing.md

File metadata and controls

137 lines (113 loc) · 4.29 KB

How to Implement Routing and Navigation img

Step 1: Basic Routing

In its simplest form the routing looks like a collection of URLs where each URL is mapped to a React component:

// client.js
import React from 'react';
import Layout from './components/Layout';
import HomePage from './components/HomePage';
import AboutPage from './components/AboutPage';
import NotFoundPage from './components/NotFoundPage';
import ErrorPage from './components/ErrorPage';

const routes = {
  '/':      <Layout><HomePage /></Layout>,
  '/about': <Layout><AboutPage /></Layout>
};

const container = document.getElementById('app');

function render() {
  try {
    const path = window.location.hash.substr(1) || '/';
    const component = routes[path] || <NotFoundPage />;
    React.render(component, container);
  } catch (err) {
    React.render(<ErrorPage {...err} />, container);
  }
}

window.addEventListener('hashchange', () => render());
render();

Step 2: Asynchronous Routes

Just wrap React components inside your routes into asynchronous functions:

import React from 'react';
import fetch from './core/fetch';
import Layout from './components/Layout';
import HomePage from './components/HomePage';
import AboutPage from './components/AboutPage';
import NotFoundPage from './components/NotFoundPage';
import ErrorPage from './components/ErrorPage';

const routes = {
  '/': async () => {
    const response = await fetch('/graphql?query={content(path:"/"){title,html}}');
    const data = await response.json();
    return <Layout><HomePage {...data} /></Layout>
  },
  '/about': async () => {
    const response = await fetch('/graphql?query={content(path:"/about"){title,html}}');
    const data = await response.json();
    return <Layout><AboutPage {...data} /></Layout>;
  }
};

const container = document.getElementById('app');

async function render() {
  try {
    const path = window.location.hash.substr(1) || '/';
    const route = routes[path];
    const component = route ? await route() : <NotFoundPage />;
    React.render(component, container);
  } catch (err) {
    React.render(<ErrorPage {...err} />, container);
  }
}

window.addEventListener('hashchange', () => render());
render();

Step 3: Parameterized Routes

(1) Convert the list of routes from hash table to an array, this way the order of routes will be preserved. (2) Wrap this collection into a Router class, where you can put .match(url) async method. (3) Use path-to-regexp to convert Express-like path strings into regular expressions which are used for matching URL paths to React components.

import React from 'react';
import Router from 'react-routing/src/Router';
import fetch from './core/fetch';
import Layout from './components/Layout';
import ProductListing from './components/ProductListing';
import ProductInfo from './components/ProductInfo';
import NotFoundPage from './components/NotFoundPage';
import ErrorPage from './components/ErrorPage';

const router = new Router(on => {
  on('/products', async () => {
    const response = await fetch('/graphql?query={products{id,name}}');
    const data = await response.json();
    return <Layout><ProductListing {...data} /></Layout>
  });
  on('/products/:id', async ({ params }) => {
    const response = await fetch('/graphql?query={product(id:"${params.id}"){name,summary}}');
    const data = await response.json();
    return <Layout><ProductInfo {...data} /></Layout>;
  });
}]);

const container = document.getElementById('app');

async function render() {
  const state = { path: window.location.hash.substr(1) || '/' };
  await router.dispatch(state, component => {
    React.render(component, container);
  });
}

window.addEventListener('hashchange', () => render());
render();

Step 4. Handling Redirects

Coming soon. Stay tuned!