@curi/react

About#

The @curi/react provides a number of React components that you can use for rendering your application.

Installation#

You can install the react package from NPM.

npm install @curi/react

If you prefer to use script tags, Unpkg will always have the latest version of react available for you.

<script src="https://unpkg.com/@curi/react@1.0.0-beta.12/dist/curi-react.js" />

There is also a minimized version available if you change the filename to react.min.js. The package will be attached to the window as window.CuriReact.

API#

The <Navigator> component provides a way to automatically re-render your application when the location changes. This component gets passed a Curi configuration object, which it will subscribe to so that it can re-render when the location changes.

import { Navigator } from '@curi/react';

const config = createConfig(history, routes);

ReactDOM.render((
  <Navigator config={config}>
    {(response, config) => {
      if (!response) {
        return null;
      }
      return response.body ? <response.body /> : null;
    }}
  </Navigator>
), holder);

A configuration object (created by calling curi's createConfig function).

A render function. This will be called whenever the <Navigator> renders. The function will be passed the current response object and the config object it was passed as a prop. The function must return a React element.

A response object. You can pass your <Navigator> a response object and it will use that instead of subscribing to the configuration object. This is ideal for server-side rendering.

A <Link> allows you to navigate within your application using an anchor element (<a>). When the rendered element is clicked, instead of reloading the page it will use your configuration object's history object to navigate.

import { Link } from '@curi/react';

With the <Link>, instead of providing a URI to navigate to, you just need to specify the name of the route you want to link to. Then, the pathname of the URI you want the component to link to will be automatically generated for you.

<Link to='User' params={{ id: 16 }}>User 16</Link>
// <a href='/user/16'>User 16</a>

The name of the route that you want to navigate to.

If the route that you want to navigate to (or any of its parents) include path parameters, you can specify them using the params prop.

// User route is { name: 'User', path: '/user/:id' }
<Link to='User' params={{ id: 16 }}>User 16</Link>

While the pathname of the location to navigate to will be generated for you, this does not cover over location properties (query, hash, and state). You can provide these values using the details prop.

<Link
  to='Products'
  params={{ type: 'vacuums' }}
  details={{ hash: 'iroomba' }}
>
  DJ Roomba
</Link>
Note: You can also include a pathname property in the details object and it will overwrite the one generated from the to prop. This isn't recommended, but does work.

By default, when you render a <Link>, an anchor element will be rendered (React.createElement('a', ...)). However, you can provide your own component to be rendered instead. This can be useful for using styled components to navigate.

Warning: You can provide any component that you want, but you should stick with an anchor (or a component that renders an anchor). There are accessibility issues that will occur when you use other DOM elements as links. The component's prop type is func in an attempt to discourage you from making your link render a button, div, span, etc.

The active prop gives you an opportunity to style the element rendered by the <Link> when it is "active". Being active means that the <Link>'s route parameters are the same as the current response's route parameters. This does not take into account any query parameters or the hash.

The active prop is an object with two properties. The first one, merge is required. The merge property must be a function. That function's argument is the props object that will be passed used to render the element rendered by the <Link>. The merge function can modify these props however it likes. It must return the resulting props object.

function mergeActive(props) {
  props.className = 'active';
  return props;
}

<Link to='Home' active={{ merge: mergeActive }}>Home</Link>

The second property of the active object is partial. By default, only <Link>s that match the response object's name can be considered "active". However, when partial is true, any parent routes can also be "active". This is done using the response object's partials property.

<Link to='Users' active={{ partial: true, merge: mergeActive }}>Users</Link>
Note: If you use the active prop, you have to include the @curi/addon-active addon in your Curi configuration object. If you do not, an error will be thrown.

<Active>#

The <Active> component allows you to style its child component as "active" when the location that <Active> describe matches the current location.

import { Active } from '@curi/react';

The <Active> component lets you modify its children element's props. It takes a merge function as a prop, which you can use to modify the child element's props when the component is "active".

Props#

name#

The name of the route to compare against the response object.

params#

An object containing route parameters. These will be compared against the route params of the response object.

children#

A React element that will have its props updated when the <Active> component is "active".

merge#

A function that will modify the children element's props. It receives a props object as its argument and must return a props object.

partial#

A boolean that defaults to false. When it is true, the "active" check will check the response's partials array in addition to its name. This allows you to style ancestor routes of the actually "active" route.

Usage#

function merge(props) {
  props.className = 'active';
  return props; 
}

const Users = (props) => (
  {
    props.users.map(u => (
      <Active
        key={u.id}
        name='User'
        merge={merge}
        params={u}
      >
        <User {...u} />
      </Active>
    ))
  }
);

This relies on the active addon from @curi/addon-active being added to your configuration object.

import createActiveAddon from '@curi/active-addon';

const config = createConfig(history, routes, {
  addons: [createActiveAddon]
});

While not strictly a requirement, the <Active> relies on the curi and curiResponse context variables existing, so your application should have a <Navigator> as an ancestor of your <Active>components in order to ensure that those exist.

<Block>#

The <Block> component lets you prevent navigation until a user has confirmed that they want to navigate. This can be useful when the user attempts to navigate away from a partially filled form. This will not prevent the user from navigating to another site, it only works for navigation within the application.

import { Block } from '@curi/react';

Props#

active#

A boolean, which is true by default. When it is true, the navigation block is active. When it is false, navigation will not be blocked.

// will block navigation
<Block active={true} confirm={confirm} />

// will not block navigation
<Block active={false} confirm={confirm} />

confirm#

The confirm prop is a function that will be called whenever there is navigation. The function will receive four arguments: location, action, success, and failure. The location and action values are the location object that is being navigated to and the type of navigation. The success and failure arguments are functions that you should call depending on whether or not you want to let the navigation happen. When the navigation should occur, the confirm function should call the success function. When the navigation should be cancelled, the failure function should be called.

<Block
  confirm={({ location, action }, success, failure) => {
    const response = window.confirm("Shall we?");
    if (response) {
      success();
    } else {
      failure();
    }
  }}
/>

curious()#

import { curious } from '@curi/react';
class MyComponent extends React.Component {
  render() {
    // because this component is wrapped with curious,
    // you can access this.props.curi and
    // this.props.response
  }
}

export default curious(MyComponent);

Props#

internalRef#

A ref function that you can use to access the wrapped component.

const WrappedComponent = curious(MyComponent);

<WrappedComponent internalRef={node => ref = node} />

Other Props#

Any other props that you pass to the wrapped component will be available to the base component.

const WrappedComponent = curious(MyComponent);

<WrappedComponent one='two' red='blue' />
// MyComponent's props: { curi: {...}, response: {...}, one: 'two', red: 'blue' }