Skip to content

The binding for the react-router that provides a new way of declaring react-router route with params validation and typescript support

License

Notifications You must be signed in to change notification settings

dev1lmini/react-router-hoc

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

63 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

React Router Route Higher-Order Component

Inspired by type-route

The binding for react-router that provides a new way of declaring react-router route with path params and query params validation and typescript support

Use cases

  • ⚗️ Declare route inside a component
  • ⛔️ Declare validation for route path and query params
  • 🚀 Generate links for a route with necessary params
  • đź’» Get suggestions in IDE

Documentation

Installation

npm i react-router-hoc react-router

The binding helps you to declare a react-router route in the component itself or in a container. Preferably this is created to define a route in the component which helps you to contain everything in one file.

Usage

Route declaration with path and query params validation

import { Route } from "react-router-hoc";

const DashboardRoute = Route(
  {
    role: Route.params.oneOf("customer", "employee"),
    region: Route.params.string,
    storage: Route.params.number.optional,
    page: Route.query.number,
    range: Route.query.oneOf('day', 'week'),
    gangs: Route.query.array(Route.query.oneOf('ballas', 'grove_street', 'lost_santos'))
  },
  ({ role, region, storage }) => `/dashboard/${role}/${region}/${storage}`
);

// Example props type
type Props = {
  user?: User;
};

export default DashboardRoute<Props>(
  ({
    user,
    match: {
      params: { role, region, storage },
       /* Set default query params if it does not match the validation rule */
      query: { page = 1, range = 'day', gangs = ['ballas']}
    },
  }) => {
    return; /** template */
  }
);

Use it as a regular route component in the router

<Router>
  <Dashboard user={user} />
</Router>
<Router>
  <Switch>
    <Home exact />
    <Dashboard user={user} />
    <NotFound />
  </Switch>
</Router>

Links generation

Generate links object

// App.tsx

import { getLinks } from 'react-router-hoc'

import Dashboard from 'Dashboard'
import Search from 'Search'
import Article from 'Article'
import Home from 'Home'

export const links = getLinks({
  Dashboard,
  Search,
  Article,
  Home
})


// Search.tsx
import { links } from 'App'
import { Link } from 'react-router-dom'
import { Route } from 'react-router-hoc'

export default Route(`/search`)(() => (
  <section>
    <Link
      /* Provide all path and query params as a single object argument */
      to={links.Dashboard({
        role: "customer",
        region: "Staryi Sambir",
        range: "week",
        page: 3
      })}
    />
  </section>
))

Generate link to the route

import Dashboard from 'Dashboard'

<Router>
  <Link to={Dashboard.link({ role: 'customer', region: 'Staryi Sambir'})}>
</Router>

Get link to the same component

If you want to change params and query params for the same route, you can use the link function from props to generate the necessary link

import { Route } from "react-router-hoc"

export default Route(
  { city: Route.query.string },
  "/search"
)(({ link }) => {
  return (
    <section>
      <input onBlur={event => link({ city: event.target.value })} />
      {city}
    </section>
  )
})

HOCs composition

Use compose to combine any HOCs with Route HOC

import { ProtectedRoute } from './your-awesome-protected-route-hoc'
import { Route, compose } from 'react-router-hoc'

const SearchRoute = compose(
  ProtectedRoute,
  Route({
    city: Route.params.string,
    page: Route.query.number
  }, ({ city}) => `/search/${city}`)
)

export default SearchRoute(() => /* template /*)

Route declaration with only path params

import { Route } from "react-router-hoc"

const SearchRoute = Route(
  { city: Route.params.string.optional },
  ({ city }) => `/search/${city}`
)

export default SearchRoute(
  ({
    match: {
      params: { city }
    }
  }) => {
    return /** template */
  }
)

Route declaration with only query params

import { Route } from "react-router-hoc"

const SearchRoute = Route(
  { age: Route.query.number },
  `/search`
)

export default SearchRoute(
  ({
    match: {
      /* Set default query param if necessary */
      query: { age = 18 }
    }
  }) => {
    return /** template */
  }
)

Route declaration without params

import { Route } from "react-router-hoc";

const HomeRoute = Route(`/home`);

export default HomeRoute(() => {
  return; /** template */
});

Curring route declaration

import { Route } from 'react-router-hoc'

export default Route(`/home`)(() =>  /** template */)

Empty route declaration (for compatibility with react-router)

import { Route } from 'react-router-hoc'

export default Route(() => /** template */)

See more examples in the repo

API

Validation rules

Route HOC provides a way to declare validation rules for path and query params, once you apply the rule it will influence route matching.

Path params

  role: Route.params.oneOf("customer", "employee"),
  region: Route.params.string,
  storage: Route.params.number,
  hash: Route.params.regex(/[0-9a-fA-f]{40}/),
  optional: Route.params.string.optional

Query params

  role: Route.query.oneOf("customer", "employee"),
  region: Route.query.string,
  storage: Route.query.number,
  hash: Route.query.regex(/[0-9a-fA-f]{40}/),
Rule Match Example
Route.params.string Match any value /:any (/228 -> '228' will be converted to a string)
Route.params.number Match only numbers /:number ('3078' -> 3078 will be converted to a number, /foo won't match the route)
Route.params.oneOf Match one of variants /customer or /employee
Route.params.regex Match a regex regex(/[0-9a-fA-f]{40}/) (ca82a6dff817ec66f44342007202690a93763949 match commit hash)
Route.params.optional Make a rule optional /any or /
Route.query.string Match any value ?param=anyValue (Any value is propagated as a string)
Route.query.number Match only numbers /params=6 ('3078' -> 3078 will be converted to a number, if no number is provided, the value will be undefined)
Route.query.oneOf Match one of variants ?param=customer or ?param=employee, if no one of these value is provided, the value will be undefined
Route.query.regex Match a regex regex(/[0-9a-fA-f]{40}/) (?hash=ca82a6dff817ec66f44342007202690a93763949 match commit hash, if the provided value doesn't match the pattern, undefined will be set to the query param)
Route.query.array(Route.query[rule]) Match array of values validate by the route ?gang=ballas&gang=mafia, will match an array of values that are validated by the other rules, if no array is provided it will be undefined, if an array doesn't contain a value that matches validation, it won't appear in an array

About

The binding for the react-router that provides a new way of declaring react-router route with params validation and typescript support

Resources

License

Stars

Watchers

Forks

Packages

No packages published