React PowerPlug is a set of pluggable renderless components and helpers that provides different types of state and logic utilities that you can use with your dumb components. It creates state and passes down the logic to the children, so you can handle your data. Read about the Render Props pattern.
- 👌 Dependency free
- 🔌 Plug and play
- 🔮 Tree shaking friendly (ESM, no side effects)
- 📦 Super tiny (~3kb)
- 📚 Well documented
- 🍻 Bunch of awesome utilities
See quick examples
import { State, Toggle } from 'react-powerplug'
import { Pagination, Tabs, Checkbox } from './MyDumbComponents'
<State initial={{ offset: 0, limit: 10, totalCount: 200 }}>
{({ state, setState }) => (
<Pagination {...state} onChange={(offset) => setState({ offset })} />
)}
</State>
<Toggle initial={true}>
{({ on, toggle }) => (
<Checkbox checked={on} onChange={toggle} />
)}
</Toggle>
// You can also use a `render` prop instead
<Toggle
initial={false}
render={({ on, toggle }) => (
<Checkbox checked={on} onChange={toggle} />
)}
/>
This branch is unstable and is in active development.
For the latest stable version go to 0.1-stable branch
Note This is a kind of a cheat sheet for fast search.
If you want a more detailed API Reference and examples for each component see full docs
Component | Component Props | Render Props | |
---|---|---|---|
<State> | { initial, onChange } |
{ state, setState } |
👇 📚 |
<Toggle> | { initial, onChange } |
{ on, toggle, set } |
👇 📚 |
<Counter> | { initial, onChange } |
{ count, inc, dec, incBy, decBy, set } |
👇 📚 |
<Value> | { initial, onChange } |
{ value, set } |
👇 📚 |
<Map> | { initial, onChange } |
{ set, get, over, values } |
👇 📚 |
<Set> | { initial, onChange } |
{ values, add, clear, remove, has } |
👇 📚 |
<List> | { initial, onChange } |
{ list, first, last, push, pull, sort, set } |
👇 📚 |
<Hover> | { onChange } |
{ hovered, bind } |
👇 📚 |
<Active> | { onChange } |
{ active, bind } |
👇 📚 |
<Focus> | { onChange } |
{ focused, bind } |
👇 📚 |
<Touch> | { onChange } |
{ touched, bind } |
👇 📚 |
<FocusManager> | { onChange } |
{ focused, blur, bind } |
👇 📚 |
<Input> | { initial, onChange } |
{ set, value, bind } |
👇 📚 |
<Form> | { initial, onChange } |
{ input, values } |
👇 📚 |
<Interval> | { delay } |
{ stop, start, toggle } |
👇 📚 |
<Compose> | { components } |
depends on components prop | 👇 📚 |
Name | |
---|---|
compose(...components) | 📚 |
composeEvents(...objOfEvents) | 📚 |
<State initial={{ loading: false, data: null }}>
{({ state, setState }) => (
<DataReceiver
data={state.data}
onStart={() => setState({ loading: true })}
onFinish={data => setState({ data, loading: false })}
/>
)}
</State>
<Toggle initial={true}>
{({ on, toggle }) => <Checkbox checked={on} onChange={toggle} />}
</Toggle>
<Counter initial={0}>
{({ count, inc, dec }) => (
<CartItem
productName="Lorem ipsum"
unitPrice={19.9}
count={count}
onAdd={inc}
onRemove={dec}
/>
)}
</Counter>
<Value initial="React">
{({ value, set }) => (
<Select
label="Choose one"
options={['React', 'Angular', 'Vue']}
value={value}
onChange={set}
/>
)}
</Value>
<Map initial={{ sounds: true, graphics: 'medium' }}>
{({ set, get }) => (
<Settings>
<ToggleCheck checked={get('sounds')} onChange={c => set('sounds', c)}>
Game Sounds
</ToggleCheck>
<Select
label="Graphics"
options={['low', 'medium', 'high']}
selected={get('graphics')}
onSelect={value => set('graphics', value)}
/>
</Settings>
)}
</Map>
<Set initial={['react', 'babel']}>
{({ values, remove, add }) => (
<TagManager>
<FormInput onSubmit={add} />
{values.map(tag => (
<Tag onRemove={() => remove(tag)}>{tag}</Tag>
))}
</TagManager>
)}
</Set>
<List initial={['Buy new shoes']}>
{({ list, pull, push }) => (
<Todo>
<TodoFormInput onSubmit={push} />
{list.map(todo => (
<TodoItem onDelete={() => pull(i => i === todo)}>
{todo}
</TodoItem>
))}
</Todo>
)}
</List>
<Hover>
{({ hovered, bind }) => (
<div {...bind}>
You are {hovered ? 'hovering' : 'not hovering'} this div.
</div>
)}
</Hover>
<Active>
{({ active, bind }) => (
<div {...bind}>
You are {active ? 'clicking' : 'not clicking'} this div.
</div>
)}
</Active>
<Touch>
{({ touched, bind }) => (
<div {...bind}>
You are {touched ? 'touching' : 'not touching'} this div.
</div>
)}
</Touch>
<Focus>
{({ focused, bind }) => (
<div>
<input {...bind} placeholder="Focus me" />
<div>You are {focused ? 'focusing' : 'not focusing'} input.</div>
</div>
)}
</Focus>
<Input initial="hello world">
{({ bind, value }) => (
<div>
<ControlledInput {...bind} />
<div>You typed {value}</div>
</div>
)}
</Input>
<Form initial={{ subject: '', message: '' }}>
{({ input, values }) => (
<form
onSubmit={e => {
e.preventDefault()
console.log(values)
}}
>
<ControlledInput placeholder="Subject" {...input('subject').bind} />
<ControlledTextArea placeholder="Message" {...input('message').bind} />
<Submit>Send</Submit>
</form>
)}
</Form>
<Interval delay={1000}>
{({ stop, start }) => (
<>
<div>The time is now {new Date().toLocaleTimeString()}</div>
<button onClick={() => stop()}>Stop interval</button>
<button onClick={() => start()}>Start interval</button>
</>
)}
</Interval>
If you want to avoid 'render props hell' you can compose two or more components in a single one.
📚 For complete guide, see docs
import { Compose } from 'react-powerplug'
<Compose components={[Toggle, Counter]}>
{(toggle, counter) => (/* ... */)}
</Compose>
import { compose } from 'react-powerplug'
const ToggleCounter = compose(
<Counter initial={5} />,
<Toggle initial={false} />
)
<ToggleCounter>
{(toggle, counter) => (
<ProductCard {...} />
)}
</ToggleCounter>
yarn add react-powerplug
npm i react-powerplug
<script src="https://unpkg.com/react-powerplug/dist/react-powerplug.min.js"></script>
exposed as ReactPowerPlug
Thanks goes to these wonderful people (emoji key):
Renato Ribeiro 💻 🎨 📖 |
Bogdan Chadkin 💻 📖 |
Travis Arnold 💻 📖 🐛 |
Max Graey 💻 |
Mateusz Burzyński 🐛 |
Andy Edwards 💻 |
Andrea Vanini 🐛 |
---|---|---|---|---|---|---|
Ivan Starkov 🐛 |
Sean Roberts 📖 |
Braden Kelley 🐛 |
This project follows the all-contributors specification. Contributions of any kind welcome!
You can help improving this project sending PRs and helping with issues.
Also you can ping me at Twitter