1.3.3 • Published 3 years ago

@rexlabs-spicerhaart/react-whereabouts v1.3.3

Weekly downloads
-
License
UNLICENSED
Repository
-
Last release
3 years ago

React utils and components for whereabouts

These utils and components compliment the core functionality of whereabouts and aim to abstract common use cases out to make development easier.

Usage

Installation

$ yarn add @rexlabs/react-whereabouts

Examples

Link

A common helper is the <Link /> component, which allows you to define links based on route objects or generic props.

import { Link } from '@rexlabs/react-whereabouts';

// Simple example
const renderLink = () =>
  <Link path='/path' query={{foo: 'bar'}} hash='some-hash'>Hello World</Link>;

// ==> <a href="/path?foo=bar#some-hash" onClick={/* History push */}>Hello World</a>

// Example with route config
const route = {
  config: {
    path: '/path/:var'
  }
}

const renderRouteLink = () =>
  <Link to={route} params={{var: 'foo'}}>Hello World</Link>;

// ==> <a href="/path/foo" onClick={/* History push */}>Hello World</a>;

You can also pass in a function as the child of <Link />, which will be rendered as a functional component receiving target, onClick, active and whereabouts as props. This way you can turn any component you want into a link.

import { Link } from '@rexlabs/react-whereabouts';

const renderLink = () =>
  <Link path='/path' hash='myhash'>
    {({ onClick }) => (
      <button onClick={onClick}>Click Me</button>
    )}
  </Link>;

// ==> <button onClick={/* History push */}>Click Me</button>;

You can also easily match the current url against a set of patterns to which the link should be indicated as active.

import { Link } from '@rexlabs/react-whereabouts';

const renderLink = () =>
  <Link to="/" activeMatches={['/', '/home']}>Welcome Home!</Link>;

// (on the homepage) ==> <a href="/" class="active">Welcome Home!</a>

You can keep the current query object for the target route like this:

<Link to={route} query={q => q}>Hello</Link>

However to make it less verbose and more readable Link additionally provides a specific prop for that use case.

<Link to={route} keepQuery>Hello</Link>

There might be cases where you'd always want to keep the query part around for specific routes, e.g. when dealing with modals. In this case you can also define the keepQuery on the route config object:

// current url: /hello?foo=bar

const ROUTE = {
  config: {
    path: '/test',
    keepQuery: true
  }
};

class Example extends React.Component {
  render () {
    return <Link to={ROUTE}>Test</Link>; // href="/test?foo=bar"
  }
}

Match

If you want to render something if the current location matches a specific pattern or route you can use the provided <Match /> component to do so.

import { Match } from `@rexlabs/react-whereabouts`;

// Example with pattern
const PatternExample = () =>
  <div>
    <Match pattern='/some/(.*)/pattern'>
      <p>
        This only renderes if the current path matches the 
        pattern `/some/(.*)/pattern` 😊
      </p>
    </Match>
  </div>;

// Example with route
const route = { config: { path: '/route/path' } };

const RouteExample = () =>
  <div>
    <Match route={route}>
      <p>Matches the route 🎉</p>
    </Match>
  </div>;

// Example with render prop pattern
const PatternExample = () =>
  <div>
    <Match pattern='/some/(.*)/pattern'>
      {match => match
        ? <p style='font-weight: bold;'>I am an active Menu Item</p>
        : <p>I am a Menu Item</p>
      }
    </Match>
  </div>;

Route config and rendering of all matching routes

Whereabouts provides the <RenderMatchedRoutes /> helper. Even though the rendering of routes is not a direct concern of the location manager (aka whereabouts), we thought it would be good to at least provide abstractions of the most common patterns for rendering to make routing implementations easier.

// Routes config
export const ROUTES = {
  HOME: {
    config: {
      path: '/',
      exact: true,
      Component: HomeScreen
    }
  },

  USERS: {
    config: {
      path: '/users',
      Component: UsersListScreen
    },

    DETAILS: {
      config: {
        path: '/users/:userId',
        Component: UserDetailsModal
      }
    }
  }
}

The structure was chosen to combine both compactness (all important information is in one place), while still maintaining readability and usability (paths e.g. are all absolute, even if nested, so that they can easily be scanned and used to render e.g. links).

You can then use <RenderMatchedRoutes /> to render all routes that are matching the current location. It will render them in the order the routes are defined in the config and will only consider sub branches if the parent node matches.

import { RenderMatchedRoutes } from '@rexlabs/react-whereabouts';
import { ROUTES } from './routes';

const App = () =>
  <RenderMatchedRoutes routes={ROUTES} />;

You can also use this config to reference routes in a meaningful way (that's where the keys in the config become important!).

import { Link } from '@rexlabs/react-whereabouts';
import { ROUTES } from './routes';

const Example = () =>
  <Link to={ROUTES.USERS.DETAILS} params={{userId: 1}}>
    Go to user #1
  </Link>;

Development

Install dependencies

$ yarn

Available Commands

$ yarn start              # starts storybook, for visual examples of (react-)whereabouts
$ yarn test               # runs all units tests
$ yarn test:watch         # runs unit tests when files change
$ yarn build              # bundles the package for production

Run examples

$ yarn && yarn start	  # starts storybook with examples at http://localhost:3000

Legal

Copyright © 2018 Rex Software All Rights Reserved.