Skip to content

QingqiShi/react-lit-store

Repository files navigation

react-lit-store

⚡️ A lightweight state management tool for React.js

npm npm bundle size Build Status codecov


Motivation

The most popular state management solution for React today is Redux. There are two problems with it:

  1. Bundle size. Using Redux will increase your bundle size by 2.6kb (redux) + 5.5kb (react-redux) = 8.1kb after gzip. (source here and here)
  2. Type checking. Type checking redux is hard. You often need to rely on implicit agreement between the actions and the reducers, and requires explicit type definitions. (source here)

Solution: ⚡️ react-lit-store

This library leverages the Context API and React Hooks to achieve less than 1kb bundle size and fantastic type checking experience.

Installation

> npm i react-lit-store

Example (Typescript)

🛠 Create stores. To create a store, all you need to do is provide an initial state and a mutations object:

/* counterStore.ts */
import { createStore } from "react-lit-store";

const initialState = { count: 3 };
type State = typeof initialState;

const mutations = {
  add: (prevState: State, amount: number) => ({
    count: prevState.count + amount
  })
};

const store = createStore(initialState, mutations);
export default store;

The mutations object is just a map between mutation names and update functions. Every mutation receives the previous state as the first argument, and the rest of the arguments are up to you. The update functions should return objects which will be merged with the state.

🎁 Wrap providers. To use the store, you need to first wrap the app with the store provider:

/* App.tsx */
import React from "react";
import CounterButton from "./CounterButton.tsx";
import counterStore from "./counterStore.ts";

function App() {
  return (
    <counterStore.Provider>
      <CounterButton />
    </counterStore.Provider>
  );
}

export default App;

You can also use the useStoreProvider utility to make this even simpler, see below.

⚡️ Use state store! You can then use the store in any of your components with the useStore hook.

/* CounterButton.tsx */
import React from "react";
import counterStore from "./counterStore.ts";

function CounterButton() {
  const [state, actions] = counterStore.useStore();
  const handleClick = () => {
    actions.add(5);
  };

  return (
    <button type="button" onClick={handleClick}>
      {state.count}
    </button>
  );
}

Actions are just named functions that, when called, fires the defined mutations using the arguments provided. Both state and actions will get full IDE integration with suggestions and type checking.

Tip: If your application requires many global state, we recommend splitting your states into seperate stores, and only import them in your components as needed. This will help minimise unnessesary rerenders.

A utility function useStoreProvider can be used to help you avoid the ugly nesting of store providers when you have many stores.

/* App.tsx */
import React from "react";
import storeA from "./storeA";
import storeB from "./storeB";
/* ... */
import { useStoreProvider } from "react-lit-store";

function App() {
  const StoreProvider = useStoreProvider(storeA, storeB /* ... */);

  return <StoreProvider>{/* ... */}</StoreProvider>;
}

export default App;

JavaScript Example

You don't have to use typescript (but then of course you won't get all the typechecking and IDE suggestions). Here's an example of a store created with pure JavaScript.

/* counterStore.ts */
import { createStore } from "libs/lit-store";

const initialState = { count: 3 };
const mutations = {
  add: (prevState, amount) => ({
    count: prevState.count + amount
  })
};

const store = createStore(initialState, mutations);
export default store;

Compatibility

react-lit-store is compile to ES5, and requires React 16.8 or higher as a peer dependency.

If you don't need to support older browsers, you can also import the following for even smaller bundle size (however for maximum compatibility we recommend the standard import):

import { createStore, useStoreProvider } from "react-lit-store/index.es";