react-floco
v0.0.6
Published
Conditional rendering helpers for react
Downloads
4
Maintainers
Readme
Quick Start
npm install --save react-floco
import { Switch, Case, Default } from 'react-floco';
/**
* Renders a status based on color
*/
function StatusFromColor (props) {
return (<Switch value={props.color}>
<Case for={"red"}>Danger!</Case>
<Case for={"orange"}>Warning!</Case>
<Case for={"green"}>All's well</Case>
<Default>Unknown</Default>
</Switch>);
}
Features
Declarative flow control for:
Support for asynchronous evaluation and rendering
Typescript support
Component library
Switch statements
The <Switch>
component controls rendering of child <Case>
components where the for
prop matches the current value
of that <Switch>
. Together, these components mimic the behavior of switch-case statements for component rendering:
import { Switch, Case, Default } from 'react-floco';
/**
* Render a badge type based on the badgeCode prop
*/
function UserBadge (props) {
return (<Switch value={props.badgeCode}>
<Case for={"p"}>Platinum badge</Case>
<Case for={"g"}>Gold badge</Case>
<Case for={"s"}>Silver badge</Case>
<Case for={"b"}>Bonze badge</Case>
<Default>No badge earned</Default>
</Switch>);
}
The <Switch>
component also allows for matching across mixed value types for <Case>
components:
<Switch value={data}>
<Case for={1}>Data {data} is a number</Case>
<Case for={true}>Data {data} is a boolean</Case>
<Case for={'foo'}>Data {data} is a string</Case>
</Switch>
Multiple <Case>
components for the same value
case are also possible:
<Switch value={data}>
<Case for={1}>Data is a number</Case>
<Case for={true}>Data is a boolean</Case>
<hr/>
<Case for={true}>Data is not false</Case>
<Case for={1}>Data is less than 5</Case>
</Switch>
The value
prop also supports callback functions - the switch automatically invokes the function and will use the result for <Case>
matching. Asynchronous values and functions are also supported:
<Switch value={() => getUserStatus()}>
<Case for={"online"}>User is onboard!</Case>
<Case for={"offline"}>User isn't around..</Case>
<Default>Hmm, not sure..</Default>
</Switch>
Conditional statements
The <If>
component controls rendering of child content when the condition
prop evaluates "truthy". If <Else>
child components are present, they will be rendered when condition
is evaluated "falsey":
import { If, Else } from 'react-floco';
/**
* Render a human friendly message based on responseIsOk prop
*/
function RenderResponse (props) {
return (<If condition={ props.responseIsOk }>
Got successful response. Everything worked as expected!
<Else>Something went wrong.</Else>
</If>);
}
As with the <Case>
and <Default>
components, multiple <Else>
components are allowed for a single <If>
component. All <Else>
components will be rendered when condition
evaluates "falsey":
<If condition={isError}>
<p>Something went wrong!</p>
<Else>Phew..</Else>
<hr/>
<Else>No error. Everything went as expected!</Else>
</If>
Like the value
prop for <Switch>
, the condition
prop also supports callback functions as well as promises:
<If condition={() => isLoggedIn()}>
<p>Welcome friend!</p>
<Else>Who goes there?</Else>
</If>
Count controlled loops
The <Repeat>
component allows a single component to be rendered multiple times. Unlike <Switch>
and <If>
, the <Repeat>
component renders children via a callback function. The render callback passes a unique key
prop that corresponds to the current iteration index:
import { Repeat } from 'react-floco';
/**
* Renders an annoying list of questions
*/
function AnnoyingList (props) {
return (<Repeat times={props.count}>
{ ({ key }) => <p key={key}>Are we there yet?</p> }
</Repeat>);
}
The render callback will automatically pass through any additional props
that are passed to <Repeat>
:
<Repeat times={5} name={'Bob'} age={32}>
{ /* props contains name and age */ }
{ (props) => <UserItem {...props} /> }
</Repeat>
Asynchronous support
The <Switch>
and <If>
components support asynchronous evaluation and rendering. If a Promise
is passed to the value
prop of the <Switch>
component, then cases will be matched on the resolved value:
<Switch value={fetchUserStatus}>
<Case for={"offline"}>User has left the building!</Case>
<Case for={"online"}>The user is online</Case>
</Switch>
If an asynchronous value
is rejected then any <Default>
blocks that are present will be rendered:
<Switch value={Promise.reject()}>
<Case for={true}>Impossible!</Case>
<Default>Either no matching case exists, or the value promise was rejected..</Default>
</Switch>
The <Loading>
component can be used in tandem with asynchronous rendering. The <Loading>
component(s) are only rendered if the value
props Promise
is in a pending state:
<Switch value={fetchEmotion}>
<Loading>I'm busy figuring someone out..</Loading>
<Case for={'happy'}>I figured out they're happy!</Case>
<Case for={'sad'}>I think they're sad!</Case>
<Default>I couldn't read them..</Default>
</Switch>
The <If>
component supports asynchronous rendering in the same way:
<If value={fetchIsHeadsFromTails}>
<Loading>The coin is spinning..</Loading>
<p>Landed on heads!</p>
<Else>Landed on tails!</Else>
</If>
API
| Component | Prop | Type | Required | Description |
| ------------- | ----------- | -------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| <Switch>
| value
| object | yes | Specifies the value that Case children will be matched against. If a function is specified, then it is invoked during rendering and the result is used for matching. |
| <Case>
| for
| object | yes | The value that this case is rendered for. |
| <If>
| condition
| bool, function | yes | Determines if the content of the component is rendered. The component is rendered if a truthy value or a function that returns a truthy value, is specified. |
| <Repeat>
| times
| number | yes | The number of times that children are rendered. |
Run tests
npm run test
Run examples
docker-compose up
License
Licensed under MIT