import { subscribe } from 'react-contextual'
subscribe
can be used as a functionwrapper or decorator, it generally works with any context, it is not bound to contextual's store model. A provider can one of the following:
- any React context
- any string key of a registered provider
- any reference to a moduleContext/namedContext provider
- any reference to a store created with createStore
Example 1: Mapping a single context value as a prop. Mapping helps performance. If you only pick the props your component is interested in it will only render when necessary and ignore context changes otherwise.
subscribe(Store, store => ({ theme: store.theme }))(AnyComponent)
Example 2: mapContextToProps behaves similar to Reduxes mapStateToProps. The component's own props can always be used as well.
subscribe(UsersContext, (users, props) => ({ user: users[props.id] }))(
AnyComponent
)
Example 3: Mapping several contexts is also possible, just wrap them into an array. The props you receive in the 2nd argument will be in the same order.
subscribe([ThemeContext, CountContext], (theme, count) => ({ theme, count }))(
AnyComponent
)
You can also pass strings to mapContextToProps to make it shorter:
subscribe(ThemeContext, 'theme')(AnyComponent)
subscribe([ThemeContext, CountContext], ['theme', 'count'])(AnyComponent)
Example 3: You can also pass a function which should return either a context object or key. You will be able to access the components props here as well.
subscribe(props => props.id, theme => ({ theme }))(AnyComponent)
If you skip the providers subscribe
will fetch react-contextuals
default context for its own store. It is basically a short cut for:
import { subscribe, ProviderContext } from 'react-contextual'
subscribe(ProviderContext, mapContextToProps)(AnyComponent)
import { Subscribe } from 'react-contextual'
The same as the higher-order-component above, but as a component: <Subscribe to={} select={}/>
. The semantics are the same, it can digest one or multiple contexts. Mapped context will be passed as a render prop. Just like subscribe
can skip the first argument and use react-contextuals
default context, so can Subscribe
if you omit the to
property.
<Subscribe to={ProviderContext} select={({ state }) => state}>
{state => <div>hi there {state.name}</div>}
</Subscribe>
import { Provider } from 'react-contextual'
A small Redux-like store. Declare props that represents the state and actions on the state. The provider will distribute the state and actions as props to listening components which either use React's API directly or contextual's subscribe
hoc to consume it. Alternatively you can pass an external store by the store
props.
The actions on the state are basically functions which return an object that is going to be merged back into the state using regular setState
semantics.
They can be simple ...
setName: name => ({ name }),
Or slightly more complex when you pass functions instead, which allow you to access the stores state, useful for computed/derived props, composition, deep-merging or memoization:
increaseCount: by => state => ({ count: state.count + by }),
Or async actions, which are supported out of the box:
setColor: backgroundColor => async state => {
await delay(1000)
return { backgroundColor }
}
import { createStore } from 'react-contextual'
const externalStore = createStore({
count: 1,
up: () => state => ({ count: state.count + 1 }),
})
Creates an external store. It takes an object that needs to specify some state and actions on the state. The store is fully reactive, that means you can read out state (store.getState()
) and call actions (store.getState().up()
) as well as store.subscribe(callback)
to it whenever it changes. If you do not specify any actions in the object passed to createStore
, a default action setState
will be created with React's semantics by default. Note: the store will only be alive once it has been tied to a provider, it won't function on its own.
const remove = externalStore.subscribe(state => console.log(state))
externalStore.getState().up()
const count = externalStore.getState().count
remove()
import { namedContext } from 'react-contextual'
name
can either be a string, in which case a context will be created under that name and you can to refer it as such in subscribe
. You can also pass a function, for instance props => props.id
. It has to return a string which will be the name of the created context.
The context will be dynamically created when the wrapped component mounts and will be removed once it unmounts. The actual context will be injected as prop (context
) so it is available for the wrapped component which can now render its Provider.
@namedContext(props => props.id)
class Theme extends React.PureComponent {
render() {
const { context: Context, children } = this.props
return <Context.Provider value="red" children={children} />
}
}
ReactDOM.render((
<Theme id="main-theme">
<Subscribe to="main-theme" select="color">{props => props.color}</Subscribe>
</Theme>,
document.getElementById('root')
)
import { moduleContext } from 'react-contextual'
Creates a global module-scoped context object and injects it both as this.props.context
into the wrapped component. Consumers can import the component and readily use it as a context provider:
@moduleContext()
class Theme extends React.PureComponent {
render() {
const { context: Context, children } = this.props
return <Context.Provider value="red" children={children} />
}
}
@subscribe(Theme, theme => ({ theme }))
class Header extends React.PureComponent {
render() {
return <h1 style={{ color: theme }}>hello</h1>
}
}
import { transformContext } from 'react-contextual'
Reads a previous context provider and provides a transformed version of its value. Think of it as a middleware.
@moduleContext()
class Theme extends React.PureComponent {
render() {
const { context, color, children } = this.props
return <context.Provider value={color} children={children} />
}
}
@transformContext(Theme, color => ({ color }))
class InvertTheme extends React.PureComponent {
render() {
const { context, color, children } = this.props
return <context.Provider value={0xffffff ^ color} children={children} />
}
}
@subscribe(Theme, color => ({ color }))
class Say extends React.PureComponent {
render() {
const { color, text } = this.props
return (
<span style={{ color: '#' + ('000000' + color.toString(16)).substr(-6) }}>
{text}
</span>
)
}
}
ReactDOM.render(
<Theme color={0xff0000}>
<Say text="all " />
<Theme color={0x00ff00}>
<Say text="is " />
<InvertTheme>
<Say text="well" />
</InvertTheme>
</Theme>
</Theme>,
document.getElementById('root')
)
import {
getNamedContext,
createNameContext,
removeNamedContext,
} from 'react-contextual'
-
createNameContext(name)
Registers and returns a context.
-
getNamedContext(name)
Returns a context.
-
removeNamedContext(name)
Removes the context from the internal map.