WrappedStateContainer
This is what is actually passed to consumers of a Context. The properties (own and inherited) of this object are what can be:
- Plucked in
Context.consume()
:
const SomeComponent = Context.consume([ 'prop1', 'prop2' ])(
({ prop1, prop2 }) => ...
)
- Dereferenced in a
<Context.Consumer>
's render prop:
<Context.Consumer>
{({ prop1, prop2 }) => ...}
</Context.Consumer>
- Dereferenced in a wrapped component's normal props:
const SomeComponent = Context.consume('store')(
({ store: { state: { prop1, prop2 } } }) => ...
)
Definition
interface WrappedStateContainer<TState> extends StateContainer<TState> {
state: ReadOnly<TState>
}
Motivation
Convenience, mostly ;)
Before React Zedux feeds the state container to consumers, it extends it with an object that contains a single property, state
. The state
property can be easily destructured in an SFC's function signature:
import { createContext } from 'react-zedux'
import { createStore } from 'zedux'
const Context = createContext(
createStore().hydrate({
hello: 'something',
world: 'spicy'
})
)
const HelloWorld = Context.inject([ 'state' ])(
({ state: { hello, world } }) => `${hello} ${world}`
)
The actual object passed to consumers looks like this:
{
state: any,
[[prototype]]: {
dispatch()
getState()
// etc...
}
}
This is called a wrapped state container. This is for performance and consumption/testing convenience. But it can be a gotcha if you don't know about it. Since the store's properties are not own properties of the wrapped state container, tests only need to specify the expected state:
expect(renderProp).toHaveBeenCalledWith({
state: 'expected state'
})
You may be tempted to write a test like this:
expect(renderProp).toHaveBeenCalledWith(store)
This'll fail. As we already stated so beautifully. But let's state it again. For fun.
The state container itself is not passed to consumers. It is first wrapped in another object.
Examples
What is actually passed to the consumers of a StoreApi?
import { StoreApi, createContext } from 'react-zedux'
import { createStore } from 'zedux'
class Api extends StoreApi {
static actors = {
anActor: () => () => 'b'
}
store = createStore().hydrate('a')
aMethod = () => {
return this.store.getState()
}
}
const Context = createContext(Api)
const SomeComponent = () => (
<Context.Injector>
{console.log}
</Context.Injector>
)
/*
logs:
{
state: 'a',
[[prototype]]: {
anActor: fn(),
aMethod: fn(),
dispatch: fn(),
getState: fn(),
...etc... (the rest of the store's methods here)
store: {
dispatch: fn(),
getState: fn()
...etc... (same thing)
}
}
}
*/