StateProvider
Make sure to first read the introduction to redux in Tabris.
This class defines the interface that connect
looks for in the global injector
instance. It provides a subset of the redux store API. This article describes the technical details of StateProvider
, but to use it properly you really just need to know how to use it to register the redux store.
Type Parameters
The StateProvider
class is a generic class with two type parameters, State
and Action
, just as the redux store. Therefore:
import {Store, createStore} from 'redux';
import {StateProvider} from 'tabris-decorators';
// Declare MyState and MyAction types...
let store: Store<MyState, MyAction>; // = createStore<MyState, MyAction>(...)
let stateProvider: StateProvider<MyState, MyAction> = store; // OK
The State
may be any type, but Action
must implement an object with an type
property: {type: any}
.
If no type parameters are given they default to the DefaultRootState
and AnyAction
interfaces, respectively. This is useful for module augmentation.
constructor
The constructor takes a single object that may implement all or part of the StateProvider
interface. That could be a redux store, any object literal with the below methods, or - technically - another instance of StateProvider
:
const stateProvider = new StateProvider<State, MyAction>({getState, subscribe, dispatch});
Methods
getState()
Returns the state that will be given to the mapStateToProps
function in connect
. The state is defined by the type parameter State
.
dispatch(action)
Returns the function that will be given to the mapDispatchToProps
function in connect
. The type of action
is defined by the type parameter Action
.
subscribe(cb)
This is the function that connect
uses to get notified about state changes. The cb
parameter is a callback function that needs to be invoked whenever getState()
does provide a new return value.
Registration
Before any connected component can be created, a StateProvider
has to be registered for dependency injection. The shortest way to do this, is to use the register
function. Since a redux store fulfills the StateProvider
interface it can be used in place of a StateProvider
instance.
import {createStore} from 'redux';
import {contentView} from 'tabris';
import {register, StateProvider} from 'tabris-decorators';
import {SomeConnectedComponent} from './SomeConnectedComponent';
// create a redux store
const store = createStore(reducer);
// register it
register(StateProvider, store);
// now we can create instances of components that use connect
contentView.append(new SomeConnectedComponent());
An alternative TypeScript-only method to register the store would be to wrap the redux store in StateProvider
and register it via @shared
:
@shared
class MyStateProvider extends StateProvider<MyState, MyAction> {
constructor() {
super(createStore(reducer));
}
}
Standalone usage
On a technical level StateProvider
is not dependent on redux. As such you may use it in any way to enable connect
to function. To implement a custom StateProvider
do this (TypeScript):
@shared
class MyStateProvider extends StateProvider<MyState, MyAction> {
constructor() {
super({});
}
getState(): MyState {
//return ...;
}
subscribe(cb: () => any) {
// handle subscribers
}
dispatch = (action: MyAction) => { //
// handle actions
return action;
};
}
Or, in JavaScript, this:
class MyStateProvider extends StateProvider {
constructor() {
super({
/** @returns {MyState} */
getState() {
//return ...;
},
subscribe(cb) {
// handle subscribers
},
/** @param {MyAction} action */
dispatch(action) {
// handle actions
return action;
}
});
}
}
register(MyStateProvider, new MyStateProvider());
It’s also possible to only override dispatch
or only getState
and subscribe
. In that case connect
can only be used with mapStateToProps
or mapDispatchToProps
, respectively.