# react-controller [![npm package][npm-badge]][npm]

[npm-badge]: https://img.shields.io/npm/v/react-controller.svg?style=flat-square
[npm]: https://www.npmjs.org/package/react-controller

[`react-controller`](https://www.npmjs.com/package/react-controller) is a component for React that takes a path, fetches a JSON response, and passes the object to its child component. Page caching, custom loading screens, prefetching and server-side rendering are made incredibly easy, especially when paired with [`react-router`](https://www.npmjs.com/package/react-router).

## Installation
```
$ npm i react-controller --save
```

```js
import Controller from 'react-controller'
```

The UMD build is also available on [unpkg](https://unpkg.com):

```html
<script src="https://unpkg.com/react-controller/umd/react-controller.min.js"></script>
```

When using the UMD build, you can find the library on `window.ReactController`.

## Basic Usage

This simplified example will make an XHR request to `/api/product/foo-bar` and pass the resulting JSON object to the `Child` component. Until the request is returned, the `ProductLoading` component will be rendered.

```js
<Controller path="/api/product/foo-bar" loadingComponent={ProductLoading}>
  <Product />
</Controller>
```

## Props

- **path** `string` (Required)<br />
The endpoint to request data from.

- **children** `function` or `ReactElement` (Required)<br />
Can be either a typical React element or a function.

- **cache** `boolean` (Default: false)<br />
Setting to `true` will store all previously requested path data in the `Controller` state.

- **initialProps** `object` (Default: null)<br />
If the app is server rendered, pass the in `initialProps` to avoid an extra XHR request when the `Controller` component mounts.

- **loadingComponent** `function` (Default: null)<br />
The React component that should render while the requested path is loading.

- **onError** `function`<br />
A function that will be called if the requested path returns anything other than a 200 header.

- **forceReload** `boolean` (Default: false)<br />
If cache is turned on, but a certain path should always make an XHR request to the server, set `forceReload` to `true`.

- **isStatic** `boolean` (Default: false)<br />
If the child component doesn’t need to make an XHR request to the server to render, then set `isStatic` to `true`.

- **options** `object` (Default: {})<br />
Object containing parameters for the request. (See the [fetch spec](https://fetch.spec.whatwg.org/).)

## Handling Errors

There are two different ways to handle errors. The first is to pass a function into the `onError` prop of the `Controller` component. If no error occurs, then the object returned from your path will be spread across your child component's props.

```js
import React from 'react'
import Controller from 'react-controller'

const ErrorHandler = ({ status }) => (
  <div>{status} status header.</div>
)

const App = () => (
  <Controller path="/api/product/foo-bar" onError={ErrorHandler}>
    <Product />
  </Controller>
)

```

The second, option is to pass a `function` as the `children` prop of `Controller`. This allows you to choose to pass only specific parts of the returned object.

```js
import React from 'react'
import Controller from 'react-controller'

const ErrorHandler = ({ status }) => (
  <div>{status} status header.</div>
)

const App = () => (
  <Controller path="/api/product/foo-bar">
    {(error, props) => error ? (
      <ErrorHandler status={error.status} />
    ) : (
      <Product {...props} />
    )}
  </Controller>
)
```

## Prefetching

If you would like to prefetch a page, use the `this.context.controller.prefetch()` function.

```js
import React, { Component } from 'react'
import PropTypes from 'prop-types'

class Homepage extends Component {
  static contextTypes = {
    controller: PropTypes.object.isRequired
  }

  componentDidMount() {   
    this.context.controller.prefetch('/products')
  }

  ...
}
```

## Example

To run the example application, run these commands from inside the `/example` directory.

```
$ npm i
$ npm start
```

View the example at [http://localhost:3000](http://localhost:3000).
