react-app-context
Application state manager based on PureComponent and React Context Api (React >= 16). Like Redux.
React context: https://reactjs.org/docs/context.html
Installation
npm i --save react-app-context
What is it?
It is one function
import initStorage from 'react-app-context';
//...
const {
Provider,
connect,
Context
} = initStorage(
defaultState,
actions,
property
);
// ...
Arguments
defaultState
- object, which contains initialize state
{
app: { ... },
users: { ... },
categories: { ... }
// ...
}
actions
- object, which contains actions functions. Each action will get state as first argument and should return new object, which will be put to context object. Action can be async function or return Promise.
{
app: {
// all actions in this path will get Context.app state part
setName: (state, newName) => ({ ...state, name: newName })
// ...
},
users: {
// all actions in this path will get Context.users state part
addUser: (state, name, login, pass) => { ... }
// ...
}
// all actions in root will get full context state object
removeStatePart: (fullState, key) => ({ ...fullState, [key]: null })
// ...
}
property
- object with options
{
debug: false // if true, debug then messages will put to console
}
Function result
This function returns object with
{
Provider, // react component
connect, // function to connect your react component to state
Context // React Context Api object
}
Provider
- simple React pureComponent, which shoud be around components, which will be get state of this Provider.
// ...
<Provider>
<MainComponentOfApp />
</Provider>
// ...
connect
- it is HOC function, which returns PureComponent above your component.
function(getNewState: function(state, props), dispatchActions: object): function(Component)
getNewState
- (state, props) => ({ ... })dispatchActions
- { myAction, ... }
// ...
export default connect(
(state, props) => ({
value: state.app.value,
isFetching: state.app.requests[props.id].isFetching
}),
{ myAction }
)(MyComponent);
// ...
How can you use it as application state like Redux?
Storage initialize
// storageConfig.js
import initStorage from 'react-app-context';
import appStorage, { actions } from './appStorage.js';
const Storage = initStorage(
{ app: appStorage },
{ app: actions },
{ debug: false }
);
export {
connect: Storage.connect
}
export default Storage.Provider;
Application storage
// appStorage.js
export default const initState = {
value: 10,
list: [],
state: 'init',
isLoading: false
};
export function setValue(state, newValue) {
return {
...state,
value: newValue
};
}
export async function getData(state) {
// it is your api function, for example
// `this` will contains
// {
// dispatch: function(function, statePropKey: string): function, - generates function with selected latest state
// actionsMap: Map[function, function], - contains all registered Actions
// call: function(function, ...args) - use to call Action
// getState: function: object - get latest state
// setState: function: Promise - works like setState of Component/PureComponent, but can be called like `await this.setState({ ... });`
// }
dispatch(state => ({ ...state, isLoading: true }), 'app')();
const newList = await myApi.getList();
return {
...state, // or ...this.getState()
list: newList,
isLoading: false
};
}
export const actions = {
setValue,
getData
};
App root component
// App.jsx
import React from 'react';
import Provider from './storageConfig';
import Toolbar from './Toolbar/Toolbar';
function App() {
return (
// all Providers childs can use `connect` function from `./storageConfig`
<Provider>
<Toolbar />
</Provider>
);
}
export default App;
Example child component
// MyButton.jsx
import React from 'react';
import { connect } from './storageConfig';
import { setValue } from './appStorage';
class MyButton extends React.PureComponent {
// `setValue` was described like `(state, newValue) => ...`
// but will be dispatched into component without state arg
// like `(newValue) => ...`
onClick = () => this.props.setValue(Math.round(Math.random() * 1000));
render() {
const { value } = this.props;
return (
<button type="button" onClick={this.onClick}>
{value}
</button>
)
}
}
export default connect(
state => ({ value: state.app.value }),
// setValue will be put into component without first argument (it was `state`)
{ setValue }
)(MyButton);
Using as state of component
react-app-context
can be used as external component state