0.3.0 • Published 5 years ago

use-global-state-context v0.3.0

Weekly downloads
-
License
MIT
Repository
github
Last release
5 years ago

use-global-state-context

Use-global-state-context is a new way to use useContext better.

build status npm version license

Features

  • Easy state management with useState and useReducer.
  • Optimally split context to prevent unnecessary renders.
  • useSelector function.
  • Support for SSR.

Why

The context API allows you to create a simple store in combination with hooks such as useState and useReducer.

However, it can lead to unnecessary renders if you don't split the context with proper granularity. It also doesn't have a feature like redux's useSelector. That means you have to memo. Please see the solutions.

On the other hand, while redux is appropriate for managing large amounts of state, I don't think it's necessary for small projects to adopt such a large library.

This library is intended to avoid the implementation costs of redux and also to prevent unnecessary renders, which is a problem with the context API.

Installation

You can install the package from npm.

npm install use-global-state-context

or using yarn.

yarn add use-global-state-context

Usage

General

import React from "react";
import { createUseStateContext } from "use-global-state-context";

// You can add global state here. easy !!
const [useGlobalState, useGlobalDispatch, ContextProvider] = createUseStateContext({
  counter: 0,
  message: "",
  app: {
    name: "use-global-state-context",
    description: "A easy global state management library",
  },
});

const App = () => (
  <ContextProvider>
    <AppName />
    <Counter />
    <CounterButton />
  </ContextProvider>
)

const Counter = () => {
  // You can get the state value of the context as follows
  const counter = useGlobalState.counter();

  return <p>counter: {counter}</p>;
};

const CounterButton = () => {
  // It only gets the dispatch; separating the state and the dispatch prevents extra renders.
  const dispatch = useGlobalDispatch();

  return (
    <>
      <button onClick={() => dispatch.counter((counter) => counter + 1)}>+ 1</button>
      <button onClick={() => dispatch.counter((counter) => counter - 1)}>- 1</button>
    </>
  );
};

const AppName = () => {
  // Like the redux useSelector API, you can retrieve only the state you need.
  // And there are no unnecessary renders.
  const name = useGlobalState.app((app) => app.name);

  return <p>App: {name}</p>;
};

export default App;

createUseStateContext API

createUseStateContext is generated by executing the values of the passed object as useState arguments, each of which is divided with appropriate granularity as a value of context.

import React from "react";
import { createUseStateContext } from "use-global-state-context";

const [useGlobalState, useGlobalDispatch, ContextProvider] = createUseStateContext({
  counter: 0,
  message: "",
  app: {
    name: "use-global-state-context",
    description: "A easy global state management library",
  }
});

You can use it as follows.

const counter = useGlobalState.counter();
// 0

const message = useGlobalState.message();
// ""

const appState = useGlobalState.app();
// {
//   name: "use-global-state-context",
//   description: "A easy global state management library",
// }

const appName = useGlobalState.app(app => app.name)
// "use-global-state-context"

const dispatch = useGlobalDispatch()
// Each of the dispatch functions
// {
//   counter: ƒ dispatchAction,
//   message: ƒ dispatchAction,
//   app: ƒ dispatchAction
// }

createUseReducerContext API

createUseReducerContext is createUseStateContext as well as generated by executing the values of the passed object as useReducer arguments, each of which is divided with appropriate granularity as a value of context.

import React from "react";
import { createUseReducerContext } from "use-global-state-context";

const initialState = {
  count: 0,
};

const ActionType = {
  INCREMENT: "INCREMENT",
  DECREMENT: "DECREMENT",
} as const;

type CounterAction = {
  type: keyof typeof ActionType;
};

const reducer: React.Reducer<typeof initialState, CounterAction> = (
  state,
  action
) => {
  switch (action.type) {
    case ActionType.INCREMENT: {
      return {
        count: state.count + 1,
      };
    }

    case ActionType.DECREMENT: {
      return {
        count: state.count - 1,
      };
    }

    default: {
      return state;
    }
  }
};

export const [useGlobalState, useGlobalDispatch, ContextProvider] = createUseReducerContext({
  counter: {
    reducer,
    initialState,
  }
});

The usage is the same as useCreateReducerContext API.

Examples

CreateUseStateContext API example

This is an example of a counter app that uses the createUseStateContext API.

Notice that each time you increase/decrease the count, only the render of the Counter comport is running. (No unnecessary renders are happening.)


CreateUseReducerContext API example

Similar to the example above, this is an example of a counter app using the createUseReducerContext API.


License

MIT © kqito