Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/theKashey/react-gearbox
⚙️📦 Gearbox - Renderless state provisioning and composition
https://github.com/theKashey/react-gearbox
compose fractal react render-props
Last synced: 3 months ago
JSON representation
⚙️📦 Gearbox - Renderless state provisioning and composition
- Host: GitHub
- URL: https://github.com/theKashey/react-gearbox
- Owner: theKashey
- License: mit
- Created: 2018-06-02T06:36:54.000Z (over 6 years ago)
- Default Branch: master
- Last Pushed: 2019-03-06T00:48:18.000Z (over 5 years ago)
- Last Synced: 2024-07-02T21:09:17.220Z (4 months ago)
- Topics: compose, fractal, react, render-props
- Language: TypeScript
- Homepage:
- Size: 199 KB
- Stars: 30
- Watchers: 3
- Forks: 1
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome-list - react-gearbox - Renderless state provisioning and composition | theKashey | 31 | (TypeScript)
README
⚙️📦 GearBox
=======
[![Build Status](https://travis-ci.org/theKashey/react-gearbox.svg?branch=master)](https://travis-ci.org/theKashey/react-gearbox)
[![coverage-badge](https://img.shields.io/codecov/c/github/thekashey/react-gearbox.svg?style=flat-square)](https://codecov.io/github/thekashey/react-gearbox)
[![NPM version](https://img.shields.io/npm/v/react-gearbox.svg)](https://www.npmjs.com/package/react-gearbox)Composes renderless containers and manages them in afterlive.
Heavily inspired by [react-adopt](https://github.com/pedronauck/react-adopt)(context compose),
[react-powerplug](https://github.com/renatorib/react-powerplug)(renderless containers)
and [redux-restate](https://github.com/theKashey/restate)(fractal state).The purpose of this library is
- (torque) combine "container"(plugs, context, states), to form more complex structure (gearbox).
- (transmission) provide a way to access them down the tree (train).
- (gear train) provide a way to alter their work (transmission).That's why - gearbox
# API
```js
import {gearbox} from 'react-gearbox';// consume any "headless" component
const State = gearbox({
name: ,
nick: ,
team: ,
enemies: Context.Consumer
});// create state and access via renderprops
{({nick}) => cos I am {nick.value}}
// create state, and access it later using train
cos I am {({nick}) => nick.value}
// unwrap powerplug using transmission
({nick: nick.value})}>
cos I am {({nick}) => nick}
```
* `gearbox(gears, options?): Gearbox` - creates a Gearbox component. Where
* `gears` is a shape of different _render-prop-ish_ components, for example:
- ReactElements, or
- FunctionalStatelessComponents, or
- Context.Consumers.
* `options` is an optional field.
- options.transmission(input, props) => output - build in transmission, to be applied on gears.
- options.defaultProps - set default props for a future component (note: defaultProps are not reflected on types, PR welcomed)Produces a `Gearbox` - renderless container, which will provide _torque_ from all gears as a render prop.
* `transmission(gearboxIn, clutch): Gearbox` - created a devired Gearbox, with "clutch" function applied to all stored data.
leftMenuController: ,
topMenuController: ,
toggler: gear(Toggle, { initial: {} }), // ~
`Gearbox` is a compound component, and includes 2 sub components
* Gearbox.train - _React Context_ based long-range torque provider, which will provide access to the parent Gearbox from the nested components.
* Gearbox.transmission - establish a local (declarative) transmission. Might not be type safe.`Gearbox` has only one prop - `render`, if not set - children is a ReactNode. If set - renderProp(function as a children)
`gear(component, props)` - a small helper to create elements, without mocking `children` prop
## Rules
- `Gearboxes` are used to combine gears together, and put them into context.
- `trains` - to access distant gearbox.
- `transmission` - to adapt data structure for the local needs.
## Adaptation
Gearbox could merge output from different component using the keys as names.
But sometimes you need a bit another structure, for example - just rename fields.
```js
import {gearbox, gear} from 'react-gearbox';
import {Toggle} from 'react-powerplug';const Gearbox = gearbox({
}, {
transmission: ({leftMenuController, topMenuController}) => ({
isLeftMenuOpen: leftMenuController.value,
isTopMenuOpen: topMenuController.value,
toggleLeftMenuOpen: leftMenuController.toggle,
toggleTopMenuOpen: topMenuController.toggle
})
});
```In the same way - you can create a new Components
```js
const Switch = gearbox({
toggle: props => ,
}, {
transmission: ({toggle}) => ({
enabled: toggle.on,
switch: toggle.toggle
}),
defaultProps: {
render: true, // render props as default
local: false, // no context support,
pure: true, // behaves as a pure component (or readux-connect)
}
});// new component adopted!
{({enabled, switch}) => ... }
```
The same technique could be used to achieve the same results as recompose's `withHandlers`
> While gearbox itself is `withState`.# Observed bits
Gearbox utilizes React.Context `observerBits` feature, not calling `Trains` if data they consume not changed.
With `pure` option enabled this gives you fine control over update propagation flow.You may opt-out by using `Gearbox.directTrain`.
```js
{({value1}) => will only update, when "value1" got updated}
{({value1}) => will update on any GearBox update}
```# Debugging
Gearbox also provides a _fancy_ debugging. Just double check React Dev Tools.
In addition:
- setDebug(boolean | function) - enableds low-level debug.
# Examples1. Create a gearbox
```js
import {gearbox} from 'react-gearbox';
import {Value, Toggle} from 'react-powerplug';
const Gearbox = gearbox({
// pass a pre-created Element, as you could do with react-adopt
storedValue: ,
// pass component, to initialize Element from props (applied only on mount)
toggle: props => ,
// pass React.Context
data: reactContext.Consumer as any, // !! "pure" consumers are not "type safe"
// or pass it as React.Element
context: ,// you may access all the gearings from above
smartComponent: (props, {data, context} /* all the props from above*/) =>
// Unstated container? Anything "render-prop" capable will work.
stated: ,
});
```2. Use Gearbox with or without renderprops
By default Gearbox __expects ReactNode as a children__, and data to be accessed via `train`, but you may specify `render` prop, to change this behavior to function-as-children.
> `render` stands for renderProps, `on` is required by `toggle`, so required by Gearbox
```js
const App = () => (
{({storedValue, toggle, data, stated}) =>...}
)
const App = () => (
...
)
```
3. Use Gearbox.train to get the data
```js
// once Gearbox is assembled - you can access it elsewhere using gear trains
const Children = () => (
{({storedValue, toggle, data, stated}) =>...}
)
```4. Use Gearbox.transmission to adopt the data
```js
// component based Transmission are NOT type safe
const Transmission = () => (
({on:toggle.on, toggle: data.toggle})}
>
{/* you may use */ }
{({on, toggle}) =>...}
)
const Transmission = () => (
({on:toggle.on, toggle: data.toggle})}
render /* use as render prop */
>
{({on, toggle}) =>...}
)
```4. Use transmission to achieve type safe transmission.
```js
const TransmittedGear = transmission(Gearbox, ({toggle, data}) => ({on:toggle.on, toggle: data.toggle}));
```
# Licence
MIT