html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block}audio:not([controls]){display:none;height:0}progress{vertical-align:baseline}[hidden],template{display:none}a{background-color:transparent;-webkit-text-decoration-skip:objects}a:active,a:hover{outline-width:0}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:inherit;font-weight:bolder}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}svg:not(:root){overflow:hidden}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}figure{margin:1em 40px}hr{box-sizing:content-box;height:0;overflow:visible}button,input,optgroup,select,textarea{font:inherit;margin:0}optgroup{font-weight:700}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-input-placeholder{color:inherit;opacity:.54}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}html{font:87.5%/1.2 -apple-system,'BlinkMacSystemFont','Segoe UI','Roboto','Oxygen-Sans','Ubuntu','Cantarell','Helvetica Neue',sans-serif;box-sizing:border-box;overflow-y:scroll;}*{box-sizing:inherit;}*:before{box-sizing:inherit;}*:after{box-sizing:inherit;}body{color:var(--app-foreground);font-family:-apple-system,'BlinkMacSystemFont','Segoe UI','Roboto','Oxygen-Sans','Ubuntu','Cantarell','Helvetica Neue',sans-serif;font-weight:normal;word-wrap:break-word;font-kerning:normal;-moz-font-feature-settings:"kern", "liga", "clig", "calt";-ms-font-feature-settings:"kern", "liga", "clig", "calt";-webkit-font-feature-settings:"kern", "liga", "clig", "calt";font-feature-settings:"kern", "liga", "clig", "calt";}img{max-width:100%;margin-left:0;margin-right:0;margin-top:0;padding-bottom:0;padding-left:0;padding-right:0;padding-top:0;margin-bottom:1.2rem;}h1{margin-left:0;margin-right:0;margin-top:0;padding-bottom:0;padding-left:0;padding-right:0;padding-top:0;margin-bottom:1.2rem;color:var(--app-purple);font-family:-apple-system,'BlinkMacSystemFont','Segoe UI','Roboto','Oxygen-Sans','Ubuntu','Cantarell','Helvetica Neue',sans-serif;font-weight:bold;text-rendering:optimizeLegibility;font-size:2rem;line-height:1.1;}h2{margin-left:0;margin-right:0;margin-top:0;padding-bottom:0;padding-left:0;padding-right:0;padding-top:0;margin-bottom:1.2rem;color:var(--app-purple);font-family:-apple-system,'BlinkMacSystemFont','Segoe UI','Roboto','Oxygen-Sans','Ubuntu','Cantarell','Helvetica Neue',sans-serif;font-weight:bold;text-rendering:optimizeLegibility;font-size:1.51572rem;line-height:1.1;}h3{margin-left:0;margin-right:0;margin-top:0;padding-bottom:0;padding-left:0;padding-right:0;padding-top:0;margin-bottom:1.2rem;color:var(--app-purple);font-family:-apple-system,'BlinkMacSystemFont','Segoe UI','Roboto','Oxygen-Sans','Ubuntu','Cantarell','Helvetica Neue',sans-serif;font-weight:bold;text-rendering:optimizeLegibility;font-size:1.31951rem;line-height:1.1;}h4{margin-left:0;margin-right:0;margin-top:0;padding-bottom:0;padding-left:0;padding-right:0;padding-top:0;margin-bottom:1.2rem;color:var(--app-purple);font-family:-apple-system,'BlinkMacSystemFont','Segoe UI','Roboto','Oxygen-Sans','Ubuntu','Cantarell','Helvetica Neue',sans-serif;font-weight:bold;text-rendering:optimizeLegibility;font-size:1rem;line-height:1.1;}h5{margin-left:0;margin-right:0;margin-top:0;padding-bottom:0;padding-left:0;padding-right:0;padding-top:0;margin-bottom:1.2rem;color:var(--app-purple);font-family:-apple-system,'BlinkMacSystemFont','Segoe UI','Roboto','Oxygen-Sans','Ubuntu','Cantarell','Helvetica Neue',sans-serif;font-weight:bold;text-rendering:optimizeLegibility;font-size:0.87055rem;line-height:1.1;}h6{margin-left:0;margin-right:0;margin-top:0;padding-bottom:0;padding-left:0;padding-right:0;padding-top:0;margin-bottom:1.2rem;color:var(--app-purple);font-family:-apple-system,'BlinkMacSystemFont','Segoe UI','Roboto','Oxygen-Sans','Ubuntu','Cantarell','Helvetica Neue',sans-serif;font-weight:bold;text-rendering:optimizeLegibility;font-size:0.81225rem;line-height:1.1;}hgroup{margin-left:0;margin-right:0;margin-top:0;padding-bottom:0;padding-left:0;padding-right:0;padding-top:0;margin-bottom:1.2rem;}ul{margin-left:1.2rem;margin-right:0;margin-top:0;padding-bottom:0;padding-left:0;padding-right:0;padding-top:0;margin-bottom:1.2rem;list-style-position:outside;list-style-image:none;}ol{margin-left:1.2rem;margin-right:0;margin-top:0;padding-bottom:0;padding-left:0;padding-right:0;padding-top:0;margin-bottom:1.2rem;list-style-position:outside;list-style-image:none;}dl{margin-left:0;margin-right:0;margin-top:0;padding-bottom:0;padding-left:0;padding-right:0;padding-top:0;margin-bottom:1.2rem;}dd{margin-left:0;margin-right:0;margin-top:0;padding-bottom:0;padding-left:0;padding-right:0;padding-top:0;margin-bottom:1.2rem;}p{margin-left:0;margin-right:0;margin-top:0;padding-bottom:0;padding-left:0;padding-right:0;padding-top:0;margin-bottom:1.2rem;}figure{margin-left:0;margin-right:0;margin-top:0;padding-bottom:0;padding-left:0;padding-right:0;padding-top:0;margin-bottom:1.2rem;}pre{margin-left:0;margin-right:0;margin-top:0;padding-bottom:0;padding-left:0;padding-right:0;padding-top:0;margin-bottom:1.2rem;font-size:0.85rem;line-height:1.2rem;}table{margin-left:0;margin-right:0;margin-top:0;padding-bottom:0;padding-left:0;padding-right:0;padding-top:0;margin-bottom:1.2rem;font-size:1rem;line-height:1.8rem;border-collapse:collapse;width:100%;}fieldset{margin-left:0;margin-right:0;margin-top:0;padding-bottom:0;padding-left:0;padding-right:0;padding-top:0;margin-bottom:1.2rem;}blockquote{margin-left:1.2rem;margin-right:1.2rem;margin-top:0;padding-bottom:0;padding-left:0;padding-right:0;padding-top:0;margin-bottom:1.2rem;}form{margin-left:0;margin-right:0;margin-top:0;padding-bottom:0;padding-left:0;padding-right:0;padding-top:0;margin-bottom:1.2rem;}noscript{margin-left:0;margin-right:0;margin-top:0;padding-bottom:0;padding-left:0;padding-right:0;padding-top:0;margin-bottom:1.2rem;}iframe{margin-left:0;margin-right:0;margin-top:0;padding-bottom:0;padding-left:0;padding-right:0;padding-top:0;margin-bottom:1.2rem;}hr{margin-left:0;margin-right:0;margin-top:0;padding-bottom:0;padding-left:0;padding-right:0;padding-top:0;margin-bottom:calc(1.2rem - 1px);background:hsla(0,0%,0%,0.2);border:none;height:1px;}address{margin-left:0;margin-right:0;margin-top:0;padding-bottom:0;padding-left:0;padding-right:0;padding-top:0;margin-bottom:1.2rem;}b{font-weight:bold;}strong{font-weight:bold;}dt{font-weight:bold;}th{font-weight:bold;}li{margin-bottom:calc(1.2rem / 2);}ol li{padding-left:0;}ul li{padding-left:0;}li > ol{margin-left:1.2rem;margin-bottom:calc(1.2rem / 2);margin-top:calc(1.2rem / 2);}li > ul{margin-left:1.2rem;margin-bottom:calc(1.2rem / 2);margin-top:calc(1.2rem / 2);}blockquote *:last-child{margin-bottom:0;}li *:last-child{margin-bottom:0;}p *:last-child{margin-bottom:0;}li > p{margin-bottom:calc(1.2rem / 2);}code{font-size:1em;line-height:1.4em;font-family:'Fira Code', monospace;}kbd{font-size:0.85rem;line-height:1.2rem;}samp{font-size:0.85rem;line-height:1.2rem;}abbr{border-bottom:1px dotted hsla(0,0%,0%,0.5);cursor:help;}acronym{border-bottom:1px dotted hsla(0,0%,0%,0.5);cursor:help;}abbr[title]{border-bottom:1px dotted hsla(0,0%,0%,0.5);cursor:help;text-decoration:none;}thead{text-align:left;}td,th{text-align:left;border-bottom:1px solid hsla(0,0%,0%,0.12);font-feature-settings:"tnum";-moz-font-feature-settings:"tnum";-ms-font-feature-settings:"tnum";-webkit-font-feature-settings:"tnum";padding-left:0.8rem;padding-right:0.8rem;padding-top:0.6rem;padding-bottom:calc(0.6rem - 1px);}th:first-child,td:first-child{padding-left:0;}th:last-child,td:last-child{padding-right:0;}a{color:inherit;}a:focus{outline:2px solid var(--app-cyan);outline-offset:0;}a:visited{color:var(--app-cyan);}code.inline{line-height:1em;background:none;}.bOFKFr{fill:currentColor;height:2em;margin:0.25em;-webkit-transform:none;-ms-transform:none;transform:none;}/*!sc*/ .etECvA{fill:currentColor;height:1em;margin:0.25em;-webkit-transform:none;-ms-transform:none;transform:none;}/*!sc*/ .crLEvQ{fill:currentColor;height:1em;margin:0.25em;-webkit-transform:rotate(-90deg);-ms-transform:rotate(-90deg);transform:rotate(-90deg);}/*!sc*/ .kpJAMR{fill:currentColor;height:1em;margin:0.25em;-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg);}/*!sc*/ data-styled.g3[id="icon__Icon-sc-1w03ldy-0"]{content:"bOFKFr,etECvA,crLEvQ,kpJAMR,"}/*!sc*/ .empDfs{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;padding:1em;border:1px solid var(--app-foreground);border-radius:var(--app-border-radius);-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;}/*!sc*/ data-styled.g4[id="example__Render-sc-1u0tgm1-0"]{content:"empDfs,"}/*!sc*/ .iXseCQ{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:end;-webkit-justify-content:flex-end;-ms-flex-pack:end;justify-content:flex-end;margin-top:0.25em;}/*!sc*/ data-styled.g5[id="example__FlexRight-sc-1u0tgm1-1"]{content:"iXseCQ,"}/*!sc*/ .eBWeFI{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;}/*!sc*/ data-styled.g6[id="example__CodeSandboxLink-sc-1u0tgm1-2"]{content:"eBWeFI,"}/*!sc*/ .iyGSwu{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;margin:0;padding:0;color:var(--app-foreground);background:none;border:none;cursor:pointer;}/*!sc*/ .iyGSwu:focus,.iyGSwu:active{color:var(--app-cyan);outline:2px solid var(--app-cyan);}/*!sc*/ data-styled.g7[id="example__ResetButton-sc-1u0tgm1-3"]{content:"iyGSwu,"}/*!sc*/ .pTvQc{max-width:100%;overflow:auto;--grvsc-border-radius:var(--app-border-radius);--grvsc-padding-h:1em;--grvsc-padding-v:1em;}/*!sc*/ .dense .default-mdx-provider__pre-sc-15gdqwx-0{margin:0;}/*!sc*/ data-styled.g8[id="default-mdx-provider__pre-sc-15gdqwx-0"]{content:"pTvQc,"}/*!sc*/ .iojkbB{border-left:2px solid var(--app-pink);padding-left:0.5em;}/*!sc*/ data-styled.g9[id="default-mdx-provider__blockquote-sc-15gdqwx-1"]{content:"iojkbB,"}/*!sc*/ .hoMCCU.slug{font-size:0.75em;margin-left:0.5em;display:none;-webkit-text-decoration:none;text-decoration:none;}/*!sc*/ *:hover > .default-mdx-provider__a-sc-15gdqwx-2.slug{display:unset;}/*!sc*/ data-styled.g10[id="default-mdx-provider__a-sc-15gdqwx-2"]{content:"hoMCCU,"}/*!sc*/ .koMXVa{margin:3em 0 1em;text-align:center;}/*!sc*/ data-styled.g12[id="footer__Container-sc-1pf7cvd-0"]{content:"koMXVa,"}/*!sc*/ .dvvVYp{color:var(--app-comment);}/*!sc*/ data-styled.g13[id="footer__Text-sc-1pf7cvd-1"]{content:"dvvVYp,"}/*!sc*/ .kCIvmz{color:var(--app-comment);}/*!sc*/ .kCIvmz:visited{color:var(--app-comment);}/*!sc*/ data-styled.g14[id="footer__Link-sc-1pf7cvd-2"]{content:"kCIvmz,"}/*!sc*/ .eeUdUW{display:grid;grid-template-areas:'title expand' 'links links';grid-template-columns:1fr auto;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;}/*!sc*/ @media (min-width:1200px){.eeUdUW{grid-template-areas:'title' 'links';grid-template-columns:unset;}}/*!sc*/ data-styled.g15[id="navigation__Container-sc-18boyty-0"]{content:"eeUdUW,"}/*!sc*/ .khCaEg{grid-area:title;margin:0;}/*!sc*/ @media (min-width:1200px){.khCaEg{margin-bottom:0.5em;}}/*!sc*/ data-styled.g16[id="navigation__Title-sc-18boyty-1"]{content:"khCaEg,"}/*!sc*/ .jyqapB{-webkit-text-decoration:none;text-decoration:none;color:var(--app-foreground);}/*!sc*/ .jyqapB:visited{color:var(--app-foreground);}/*!sc*/ data-styled.g17[id="navigation__TitleLink-sc-18boyty-2"]{content:"jyqapB,"}/*!sc*/ .iKXeho{grid-area:expand;color:var(--app-foreground);width:50px;height:50px;background:none;border:none;margin:0;padding:0;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;}/*!sc*/ .iKXeho:focus,.iKXeho:active{color:var(--app-pink);outline:2px solid var(--app-pink);}/*!sc*/ @media (min-width:1200px){.iKXeho{display:none;}}/*!sc*/ data-styled.g18[id="navigation__Expand-sc-18boyty-3"]{content:"iKXeho,"}/*!sc*/ .ktoYoz{grid-area:links;display:none;}/*!sc*/ @media (min-width:1200px){.ktoYoz{display:unset;}}/*!sc*/ data-styled.g19[id="navigation__Links-sc-18boyty-4"]{content:"ktoYoz,"}/*!sc*/ .bwEVJA{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;font-size:1.2em;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;}/*!sc*/ data-styled.g20[id="prev-next__StyledLinkToSlug-sel85m-0"]{content:"bwEVJA,"}/*!sc*/ .fhnjmd{display:grid;grid-template-areas:'left-void nav right-void' 'left-void content right-void';grid-template-columns:1fr minmax(0,85ch) 1fr;padding:0 0.5rem;}/*!sc*/ @media (min-width:1200px){.fhnjmd{grid-template-areas:'nav content void';grid-template-columns:1fr 85ch 1fr;padding:1rem;max-width:150ch;margin:0 auto;}}/*!sc*/ data-styled.g21[id="default__Grid-cc4rlb-0"]{content:"fhnjmd,"}/*!sc*/ .giaaSE{grid-area:nav;}/*!sc*/ data-styled.g22[id="default__NavigationSlot-cc4rlb-1"]{content:"giaaSE,"}/*!sc*/ .hVUruk{grid-area:content;}/*!sc*/ data-styled.g23[id="default__Content-cc4rlb-2"]{content:"hVUruk,"}/*!sc*/ .iBPGgH{display:grid;grid-template-areas:'next' 'prev';}/*!sc*/ @media (min-width:576px){.iBPGgH{grid-template-areas:'prev void next';grid-template-columns:auto 1fr auto;}}/*!sc*/ data-styled.g24[id="default__Paging-cc4rlb-3"]{content:"iBPGgH,"}/*!sc*/ .bDSAqh{grid-area:prev;}/*!sc*/ data-styled.g25[id="default__StyledPrev-cc4rlb-4"]{content:"bDSAqh,"}/*!sc*/ .dmuBWa{grid-area:next;justify-self:flex-end;}/*!sc*/ data-styled.g26[id="default__StyledNext-cc4rlb-5"]{content:"dmuBWa,"}/*!sc*/

Routing

Why?

  • navigating makes the page reload
  • without caching it can be slow
  • avoid page reloads by using a router

How?

Using react-router

  • the following is just an overview, the docs are more detailed

Router

examples use a custom Router based on MemoryRouter

Route

  • docs
  • matches path to components
  • multiple can be active
  • can be nested, side-by-side
  • fully dynamic
  • can have params /some/route/:param

Switch

  • docs
  • ensures that only one Route is active at a time
  • use for fallback (404) routes
  • docs
  • replaces a tags to avoid reloads
  • NavLink can be used to apply “active styles” docs

Redirect

  • docs
  • when rendered, redirect to to prop
  • use it to keep old links working

useParams

  • docs
  • get hold of params in your components

Simple

import React, { FC } from 'react'
import { Route, Switch } from 'react-router'
import { Link } from 'react-router-dom'

export const Simple: FC = () => {
  return (
    <Switch>
      <Route path="/lorem">lorem</Route>
      <Route path="/ipsum">ipsum</Route>
      <Route path="/dolor">dolor</Route>
      <Route path="/">
        <h1>Home</h1>
        <ul>
          <li>
            <Link to="/lorem">lorem</Link>
          </li>
          <li>
            <Link to="/ipsum">ipsum</Link>
          </li>
          <li>
            <Link to="/dolor">dolor</Link>
          </li>
        </ul>
      </Route>
    </Switch>
  )
}

export default <Simple />
lorem
  • ipsum
  • dolor
  • 404 Page

    import React, { FC } from 'react'
    import { NavLink, Route, Switch } from 'react-router-dom'
    import classes from './example.module.css'
    
    export const NavBar: FC = () => {
      return (
        <nav>
          <NavLink to="/" exact activeClassName={classes.activeLink}>
            home
          </NavLink>
          {' '}
          <NavLink to="/pricing" activeClassName={classes.activeLink}>
            pricing
          </NavLink>
          {' '}
          <NavLink to="/about" activeClassName={classes.activeLink}>
            about
          </NavLink>
          {' '}
          <NavLink
            to="/this-page-does-not-exist"
            activeClassName={classes.activeLink}
          >
            broken link
          </NavLink>
        </nav>
      )
    }
    
    export const Example: FC = () => {
      return (
        <div>
          <NavBar />
          <article>
            <Switch>
              <Route path="/pricing">pricing page</Route>
              <Route path="/about">about page</Route>
              <Route path="/" exact>
                home page
              </Route>
              <Route path="/">404 page</Route>
            </Switch>
          </article>
        </div>
      )
    }
    
    export default <Example />
    home pricing about broken link
    home page

    Using Params

    import React, { FC } from 'react'
    import { Redirect, Route, Switch, useParams } from 'react-router'
    import { Link } from 'react-router-dom'
    import { Database } from './database'
    
    export const Article: FC = () => {
      const { articleId } = useParams<{ articleId: string }>()
      const article = Database.getArticleById(Number(articleId))
      const user = article && Database.getUserById(article.owner)
    
      return (
        <div>
          {user && article ? (
            <div>
              <h1>{article.title}</h1>
              <p>{article.content}</p>
              <Link to={`/user/${user.id}`}>
                <i>by {user.name}</i>
              </Link>
            </div>
          ) : (
            <h1>Cannot find article</h1>
          )}
        </div>
      )
    }
    
    export const User: FC = () => {
      const { userId } = useParams<{ userId: string }>()
      const user = Database.getUserById(userId)
      const articles = user ? user.articles.map(Database.getArticleById) : []
    
      return (
        <div>
          {user ? (
            <div>
              <h1>Posts from {user.name}</h1>
              {articles.length ? (
                <ul>
                  {articles.map((article) => {
                    if (!article) throw new Error()
                    const { title, id } = article
                    return (
                      <li key={id}>
                        <Link to={`/article/${id}`}>{title}</Link>
                      </li>
                    )
                  })}
                </ul>
              ) : (
                <p>{user.name} has no articles</p>
              )}
            </div>
          ) : (
            <h1>Cannot find user with id {userId}</h1>
          )}
        </div>
      )
    }
    
    export const Users: FC = () => {
      const users = Database.getUsers()
      return (
        <div>
          <h1>Users</h1>
          <ul>
            {users.map(({ id, name }) => (
              <li key={id}>
                <Link to={`/user/${id}`}>{name}</Link>
              </li>
            ))}
          </ul>
        </div>
      )
    }
    
    export const Params: FC = () => {
      return (
        <Switch>
          <Route path="/users">
            <Users />
          </Route>
          <Route path="/user/:userId">
            <User />
          </Route>
          <Route path="/article/:articleId">
            <Article />
          </Route>
          <Route path="/">
            <Redirect to="/users" />
          </Route>
        </Switch>
      )
    }
    
    export default <Params />