contextual
Unceremonious application state
Installation
npm i @rognstadragnar/contextual
Basic usage
Provider
components
Step 1: Create They must wrap whatever wants to consume their state and actions.
import { h, Component } from 'preact'
import { Provider } from '@rognstadragnar/contextual'
import { Something } from './somwhere'
export class CounterContainer extends Component {
state = {
count: 0
}
increment = todo => {
const count = this.state.count + 1
this.setState({ count })
}
decrement = todo => {
const count = this.state.count - 1
this.setState({ count })
}
render() {
return (
<Provider
name="counter-state"
state={{ count: this.state.count }}
actions={{
increment: this.increment,
decrement: this.decrement
}}
>
<Something />
</Provider>
)
}
}
<Consumer />
components
Step 2: Create They can be used anywhere in your component tree as long as the <Provider />
they consume wraps them.
State and actions from the <Provider />
can be leveraged in ceveral ways:
- Functions that return components
- Components injected with state and actions
- TODO: Render property
-
TODO: Consume/connect wrapper functions like
react-redux
1. Functions as consumer children
import { h, Component } from 'preact'
import { Consumer } from '@rognstadragnar/contextual'
const SomeComponent = ({ count, increment, decrement }) => {
return (
<main>
<h1>{count}</h1>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
</main>
)
}
export const Something = () => {
return (
<Consumer consumes="counter-state">
{(state, actions) => (
<SomeComponent
count={state.count}
increment={actions.increment}
decrement={actions.decrement}
/>
)}
</Consumer>
)
}
2. Components with injectable props as consumer children
import { h, Component } from 'preact'
import { Consumer } from '@rognstadragnar/contextual'
const SomeComponent = ({ state, actions }) => {
return (
<main>
<h1>{state.count}</h1>
<button onClick={actions.increment}>Increment</button>
<button onClick={actions.decrement}>Decrement</button>
</main>
)
}
export const Something = () => {
return (
<Consumer consumes="counter-state">
<MyComponent />
</Consumer>
)
}
3. TODO: Render property
import { h, Component } from 'preact'
import { Consumer } from '@rognstadragnar/contextual'
const SomeComponent = ({ count, increment, decrement }) => {
return (
<main>
<h1>{count}</h1>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
</main>
)
}
export const Something = () => {
return (
<Consumer
consumes="counter-state"
render={(state, actions) => (
<SomeComponent
count={state.count}
increment={actions.increment}
decrement={actions.decrement}
/>
)}
// or like this, similiar to #3
render={<SomeComponent />}
/>
)
}
4. TODO: React-redux inspired consume/connect function
import { h, Component } from 'preact'
import { Consumer } from '@rognstadragnar/contextual'
const MyComponent = ({ state, actions }) => {
return (
<main>
<h1>{state.count}</h1>
<button onClick={actions.increment}>Increment</button>
<button onClick={actions.decrement}>Decrement</button>
</main>
)
}
export const Something = consume({ consumes: 'counter-state' })(MyComponent)
Properties
<Provider />
Property | Type | Description | Required |
---|---|---|---|
name |
string |
identifier used if multiple <Provider /> in one app |
Yes, if using more than one <Provider />
|
state |
any |
State available to consumers throughout the app | No |
actions |
any |
Actions available throughout the app | No |
<Consumer />
Property | Type | Description | Required |
---|---|---|---|
consumes |
string or string[]
|
Which <Provider /> it consumes |
Yes |
children (regular) |
Component<{state, actions}> or (state, actions) => Component<{state, actions}>
|
The children of the <Consumer />
|
Yes |
TODO: render
|
Component<{state, actions}> or (state, actions) => Component<{state, actions}>
|
Instead of chidren | No |
mapStateToProps |
null or (state) => any
|
Extract or transform the state provided to the consumer | No |
mapActionsToProps |
null or (actions, state) => any
|
Extract or transform the actions provided to the consumer | No |
fragment |
Component or (children) => Component
|
Wraps the children. Default: nothing or <span /> if children.length > 2
|
No |
Note:
- If using either
mapStateToProps
,mapActionsToProps
or both, props will be flattened like so{ ...state, ...actions, ...rest }
- If
consumes
is an array of strings (e.g.<Consumer consumes={['a', 'b']} />
, each will be object properties of the state and actions (e.g.{ a: ..., b: ... }
)
Examples
License
MIT.