Skip to content

axules/react-app-context

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

26 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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