Skip to content
This repository has been archived by the owner on Nov 10, 2023. It is now read-only.

Commit

Permalink
Merge pull request #3 from jxom/v4
Browse files Browse the repository at this point in the history
v4
  • Loading branch information
jxom authored May 10, 2018
2 parents a5cb440 + d07b45b commit b6ace06
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 184 deletions.
79 changes: 16 additions & 63 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,26 +36,24 @@ $ npm install react-loads

```js
import React from 'react';
import Loads, { IfIdle, IfLoading, IfTimeout, IfSuccess, IfError } from 'react-loads';
import Loads from 'react-loads';

const getRandomDog = () => axios.get('https://dog.ceo/api/breeds/image/random');

export default () => (
<Loads fn={getRandomDog}>
{({ load, response, error }) => (
{({ isIdle, isLoading, isSuccess, load, response, state, error }) => (
<div>
<IfIdle>
<button onClick={load}>Load random dog</button>
</IfIdle>
<IfLoading>loading...</IfLoading>
<IfTimeout>taking a while...</IfTimeout>
<IfSuccess>
{response && <img src={response.data.message} alt="Dog" />}
{isIdle && <button onClick={load}>Load random dog</button>}
{isLoading && <div>loading...</div>}
{isSuccess && (
<div>
<button onClick={load}>Load another dog</button>
{response && <img src={response.data.message} alt="Dog" />}
<div>
<button onClick={load}>Load another dog</button>
</div>
</div>
</IfSuccess>
<IfError>Error! {error}</IfError>
)}
</div>
)}
</Loads>
Expand All @@ -76,7 +74,7 @@ export default () => (
<table>
<thead><tr><th>Prop</th><th>Type</th><th>Default value</th><th>Description</th></tr></thead>
<tbody>
<tr><td> children </td><td><code>({ response?: any, error?: any, load: (...args: any) => ?Promise&lt;any&gt;, reset: Function, state: 'idle' | 'loading' | 'timeout' | 'success' | 'error' })</code></td><td>N/A (required)</td> <td></td></tr>
<tr><td> children </td><td><code>({ response?: any, error?: any, load: (...args: any) => ?Promise&lt;any&gt;, resetState: Function })</code></td><td>N/A (required)</td> <td></td></tr>
<tr><td> delay </td><td><code>number</code></td><td><code>300</code></td> <td>Number of milliseconds before component transitions to <code>loading</code> state upon invoking <code>fn</code>/<code>load</code>.</td></tr>
<tr><td> loadOnMount </td><td><code>boolean</code></td><td><code>false</code></td> <td>Whether or not to invoke the <code>fn</code> on mount.</td></tr>
<tr><td> fn </td><td><code>(...args: any) => Promise&lt;any&gt;</code></td><td>N/A (required)</td> <td>The promise to invoke.</td></tr>
Expand All @@ -92,60 +90,15 @@ export default () => (
<tr><td> response </td><td><code>any</code></td><td>Response from the resolved promise (`fn`)</td></tr>
<tr><td> error </td><td><code>any</code></td><td>Error from the rejected promise (`fn`)</td></tr>
<tr><td> load </td><td><code>(...args: any) => ?Promise&lt;any&gt;</code></td><td>Trigger to load `fn`</td></tr>
<tr><td> isIdle </td><td><code>boolean</code></td><td>Returns `true` if the state is idle (`fn` has not been triggered).</td></tr>
<tr><td> isLoading </td><td><code>boolean</code></td><td>Returns `true` if the state is loading (`fn` is in a pending state).</td></tr>
<tr><td> isTimeout </td><td><code>boolean</code></td><td>Returns `true` if the state is timeout (`fn` is in a pending state for longer than `delay` milliseconds).</td></tr>
<tr><td> isSuccess </td><td><code>boolean</code></td><td>Returns `true` if the state is success (`fn` has been resolved).</td></tr>
<tr><td> isError </td><td><code>boolean</code></td><td>Returns `true` if the state is error (`fn` has been rejected).</td></tr>
<tr><td> resetState </td><td><code>() => void</code></td><td>Reset state back to `idle`.</td></tr>
<tr><td> state </td><td><code>'idle' | 'loading' | 'timeout' | 'success' | 'error'</code></td><td>Current state.</td></tr>
</tbody>
</table>

### `<IfIdle>`, `<IfLoading>`, `<IfTimeout>`, `<IfSuccess>`, `<IfError>`

These components determine what node to render based on the loading/response state.

#### Definitions

- `IfIdle` - Will render when the state is 'idle' (the initial state).
- `IfLoading` - Will render when the state is 'loading' (triggered when the promise (`fn`) is pending).
- `IfTimeout` - Will render when the state is 'timeout' (triggered when the promise (`fn`) has not resolved/rejected after a period of time).
- `IfSuccess` - Will render when the state is 'success' (triggered when the promise (`fn`) resolves).
- `IfError` - Will render when the state is 'error' (triggered when the promise (`fn`) rejects).

#### Props

<table>
<thead><tr><th>Prop</th><th>Type</th><th>Default value</th><th>Description</th></tr></thead>
<tbody>
<tr><td>channel</td><td>string</td><td><code>null</code></td> <td>The key of the context from where to read the state.</td></tr>
<tr><td>children</td><td>node</td><td>N/A (required)</td> <td>The children to be rendered when the
conditions match.</td></tr>
<tr><td>onShow</td><td>func</td><td></td> <td>The function invoked when the component becomes visible.</td></tr>
<tr><td>onHide</td><td>func</td><td></td> <td>The function invoked when the component becomes hidden.</td></tr>
</tbody>
</table>

### `<IfState>`

A component to define which parts of the tree should be rendered for a set of states.

#### Props

<table>
<thead><tr><th>Prop</th><th>Type</th><th>Default value</th><th>Description</th></tr></thead>
<tbody>
<tr><td>is</td><td>oneOfType(arrayOf(string), string)</td><td>N/A (required)</td> <td>The states(s) for which the children should be shown. Available states: <code>'idle'</code>, <code>'loading'</code>, <code>'timeout'</code>, <code>'success'</code>, <code>'error'</code></td></tr>
<tr><td>channel</td><td>string</td><td><code>null</code></td> <td>The key of the context from where to read the state.</td></tr>
<tr><td>children</td><td>node</td><td>N/A (required)</td> <td>The children to be rendered when the
conditions match.</td></tr>
<tr><td>onShow</td><td>func</td><td></td> <td>The function invoked when the component becomes visible.</td></tr>
<tr><td>onHide</td><td>func</td><td></td> <td>The function invoked when the component becomes hidden.</td></tr>
</tbody>
</table>

```jsx
<IfState is={['idle', 'success']}>
Hello world!
</IfState>
```

## Special thanks

- [Michele Bertoli](https://github.com/MicheleBertoli) for creating [React Automata](https://github.com/MicheleBertoli/react-automata) - it's awesome and you should check it out.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-loads",
"version": "3.1.0",
"version": "4.0.0-canary.1",
"description": "A simple React component to handle loading state",
"license": "MIT",
"repository": "jxom/react-loads",
Expand Down
186 changes: 97 additions & 89 deletions src/__stories__/index.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,26 @@
import React, { Fragment } from 'react';
import { storiesOf } from '@storybook/react';
import axios from 'axios';
import Loads, { IfState, IfIdle, IfLoading, IfSuccess, IfTimeout, IfError } from '../index';
import Loads from '../index';

storiesOf('Loads', module)
.add('default usage', () => {
const getRandomDog = () => axios.get('https://dog.ceo/api/breeds/image/random');
return (
<Loads fn={getRandomDog}>
{({ load, response, state, error }) => (
{({ isIdle, isLoading, isSuccess, load, response, state, error }) => (
<div>
<p>Current state: {state}</p>
<IfIdle>
<button onClick={load}>Load random dog</button>
</IfIdle>
<IfLoading>loading...</IfLoading>
<IfSuccess>
{response && <img src={response.data.message} alt="Dog" />}
{isIdle && <button onClick={load}>Load random dog</button>}
{isLoading && <div>loading...</div>}
{isSuccess && (
<div>
<button onClick={load}>Load another dog</button>
{response && <img src={response.data.message} alt="Dog" />}
<div>
<button onClick={load}>Load another dog</button>
</div>
</div>
</IfSuccess>
<IfError>Error! {error}</IfError>
)}
</div>
)}
</Loads>
Expand All @@ -33,20 +32,19 @@ storiesOf('Loads', module)
const getRandomDog = () => axios.get('https://dog.ceo/api/breeds/image/random');
return (
<Loads loadOnMount fn={getRandomDog}>
{({ load, response, state, error }) => (
{({ isIdle, isLoading, isSuccess, load, response, state, error }) => (
<div>
<p>Current state: {state}</p>
<IfIdle>
<button onClick={load}>Load random dog</button>
</IfIdle>
<IfLoading>loading...</IfLoading>
<IfSuccess>
{response && <img src={response.data.message} alt="Dog" />}
{isIdle && <button onClick={load}>Load random dog</button>}
{isLoading && <div>loading...</div>}
{isSuccess && (
<div>
<button onClick={load}>Load another dog</button>
{response && <img src={response.data.message} alt="Dog" />}
<div>
<button onClick={load}>Load another dog</button>
</div>
</div>
</IfSuccess>
<IfError>Error! {error}</IfError>
)}
</div>
)}
</Loads>
Expand All @@ -56,20 +54,19 @@ storiesOf('Loads', module)
const getRandomDog = () => axios.get('https://dog.ceo/api/breeds/image/random');
return (
<Loads delay={1500} fn={getRandomDog}>
{({ load, response, state, error }) => (
{({ isIdle, isLoading, isSuccess, load, response, state, error }) => (
<Fragment>
<p>Current state: {state}</p>
<IfIdle>
<button onClick={load}>Load random dog</button>
</IfIdle>
<IfLoading>loading...</IfLoading>
<IfSuccess>
{response && <img src={response.data.message} alt="Dog" />}
{isIdle && <button onClick={load}>Load random dog</button>}
{isLoading && <div>loading...</div>}
{isSuccess && (
<div>
<button onClick={load}>Load another dog</button>
{response && <img src={response.data.message} alt="Dog" />}
<div>
<button onClick={load}>Load another dog</button>
</div>
</div>
</IfSuccess>
<IfError>Error! {error}</IfError>
)}
</Fragment>
)}
</Loads>
Expand All @@ -79,20 +76,19 @@ storiesOf('Loads', module)
const getRandomDog = () => axios.get('https://dog.ceo/api/breeds/image/random');
return (
<Loads delay={0} fn={getRandomDog}>
{({ load, response, state, error }) => (
{({ isIdle, isLoading, isSuccess, load, response, state, error }) => (
<Fragment>
<p>Current state: {state}</p>
<IfIdle>
<button onClick={load}>Load random dog</button>
</IfIdle>
<IfLoading>loading...</IfLoading>
<IfSuccess>
{response && <img src={response.data.message} alt="Dog" />}
{isIdle && <button onClick={load}>Load random dog</button>}
{isLoading && <div>loading...</div>}
{isSuccess && (
<div>
<button onClick={load}>Load another dog</button>
{response && <img src={response.data.message} alt="Dog" />}
<div>
<button onClick={load}>Load another dog</button>
</div>
</div>
</IfSuccess>
<IfError>Error! {error}</IfError>
)}
</Fragment>
)}
</Loads>
Expand All @@ -104,20 +100,20 @@ storiesOf('Loads', module)
};
return (
<Loads fn={getRandomDog}>
{({ load, response, state, error }) => (
{({ isIdle, isLoading, isSuccess, isError, load, response, state, error }) => (
<Fragment>
<p>Current state: {state}</p>
<IfIdle>
<button onClick={load}>Load random dog</button>
</IfIdle>
<IfLoading>loading...</IfLoading>
<IfSuccess>
{response && <img src={response.data.message} alt="Dog" />}
{isIdle && <button onClick={load}>Load random dog</button>}
{isLoading && <div>loading...</div>}
{isSuccess && (
<div>
<button onClick={load}>Load another dog</button>
{response && <img src={response.data.message} alt="Dog" />}
<div>
<button onClick={load}>Load another dog</button>
</div>
</div>
</IfSuccess>
<IfError>Error! {error && error.message}</IfError>
)}
{isError && <div>Error! {error}</div>}
</Fragment>
)}
</Loads>
Expand All @@ -128,21 +124,20 @@ storiesOf('Loads', module)
new Promise(resolve => setTimeout(() => resolve(axios.get('https://dog.ceo/api/breeds/image/random')), 3000));
return (
<Loads timeout={1500} fn={getRandomDog}>
{({ load, response, state, error }) => (
{({ isIdle, isLoading, isSuccess, isTimeout, load, response, state, error }) => (
<Fragment>
<p>Current state: {state}</p>
<IfIdle>
<button onClick={load}>Load random dog</button>
</IfIdle>
<IfLoading>loading...</IfLoading>
<IfTimeout>taking a while...</IfTimeout>
<IfSuccess>
{response && <img src={response.data.message} alt="Dog" />}
{isIdle && <button onClick={load}>Load random dog</button>}
{isLoading && <div>loading...</div>}
{isTimeout && <div>taking a while...</div>}
{isSuccess && (
<div>
<button onClick={load}>Load another dog</button>
{response && <img src={response.data.message} alt="Dog" />}
<div>
<button onClick={load}>Load another dog</button>
</div>
</div>
</IfSuccess>
<IfError>Error! {error && error.message}</IfError>
)}
</Fragment>
)}
</Loads>
Expand All @@ -152,20 +147,19 @@ storiesOf('Loads', module)
const getRandomDogByBreed = breed => axios.get(`https://dog.ceo/api/breed/${breed}/images/random`);
return (
<Loads fn={getRandomDogByBreed}>
{({ load, response, state, error }) => (
{({ isIdle, isLoading, isSuccess, load, response, state, error }) => (
<div>
<p>Current state: {state}</p>
<IfIdle>
<button onClick={() => load('beagle')}>Load random beagle</button>
</IfIdle>
<IfLoading>loading...</IfLoading>
<IfSuccess>
{response && <img src={response.data.message} alt="Dog" />}
{isIdle && <button onClick={() => load('beagle')}>Load random beagle</button>}
{isLoading && <div>loading...</div>}
{isSuccess && (
<div>
<button onClick={() => load('beagle')}>Load another beagle</button>
{response && <img src={response.data.message} alt="Dog" />}
<div>
<button onClick={() => load('beagle')}>Load another beagle</button>
</div>
</div>
</IfSuccess>
<IfError>Error! {error}</IfError>
)}
</div>
)}
</Loads>
Expand All @@ -175,26 +169,40 @@ storiesOf('Loads', module)
const getRandomDog = () => axios.get(`https://dog.ceo/api/breeds/image/random`);
const saveDog = randomDogResponse => new Promise(resolve => setTimeout(() => resolve(randomDogResponse), 1000));
return (
<Loads channel="randomDog" fn={getRandomDog}>
{({ load: loadRandomDog, response: randomDogResponse, error: randomDogError }) => (
<Loads channel="saveDog" fn={saveDog}>
{({ load: saveDog, state: saveDogState }) => (
<Loads fn={getRandomDog}>
{({
isIdle: isRandomDogIdle,
isLoading: isRandomDogLoading,
isError: isRandomDogError,
isSuccess: isRandomDogSuccess,
load: loadRandomDog,
response: randomDogResponse,
error: randomDogError
}) => (
<Loads fn={saveDog}>
{({
isLoading: isSaveDogLoading,
isSuccess: isSaveDogSuccess,
isIdle: isSaveDogIdle,
load: saveDog,
state: saveDogState
}) => (
<div>
<IfIdle channel="randomDog">
<button onClick={loadRandomDog}>Load random dog</button>
</IfIdle>
<IfLoading channel="randomDog">loading...</IfLoading>
<IfSuccess channel="randomDog">
{randomDogResponse && <img src={randomDogResponse.data.message} alt="Dog" />}
{isRandomDogIdle && <button onClick={loadRandomDog}>Load random dog</button>}
{isRandomDogLoading && <div>loading...</div>}
{isRandomDogSuccess && (
<div>
<IfLoading channel="saveDog">saving...</IfLoading>
<IfSuccess channel="saveDog">saved dog!</IfSuccess>
<IfState is={['idle', 'success']} channel="saveDog">
<button onClick={() => saveDog(randomDogResponse)}>Save dog</button>
</IfState>
{randomDogResponse && <img src={randomDogResponse.data.message} alt="Dog" />}
<div>
{isSaveDogLoading && <div>saving...</div>}
{isSaveDogSuccess && <div>saved dog!</div>}
{(isSaveDogSuccess || isSaveDogIdle) && (
<button onClick={() => saveDog(randomDogResponse)}>Save dog</button>
)}
</div>
</div>
</IfSuccess>
<IfError channel="randomDog">Error! {randomDogError}</IfError>
)}
{isRandomDogError && <div>Error! {randomDogError}</div>}
</div>
)}
</Loads>
Expand Down
Loading

0 comments on commit b6ace06

Please sign in to comment.