rehooks/ideas

useLocalStorageReducer

iamsolankiamit opened this issue · 0 comments

Reducer with state synced with localStorage. Would be great for syncing state between tabs and sessions.

Basic initial Implementation would look like this

import React, { useReducer, useEffect } from "react";
import { render } from "react-dom";
import useLocalStorage from '@rehooks/local-storage';

function useLocalStorageReducer({ reducerKey, transformer }, reducer, initialState, initialAction) {
  let localState = useLocalStorage(reducerKey);
  if (localState) {
    localState = JSON.parse(localState);
    localState = transformer(localState);
  } else {
    localState = initialState;
  }

  const [state, dispatch] = useReducer(reducer, localState, initialAction);
  useEffect(
    () => {
      localStorage.setItem(reducerKey, JSON.stringify(state));
    },
    [state]
  );
  return [state, dispatch];
}

const initialState = { count: 0 };

function reducer(state, action) {
  switch (action.type) {
    case "reset":
      return { count: action.payload };
    case "increment":
      return { count: state.count + 1 };
    case "decrement":
      return { count: state.count - 1 };
    default:
      return state;
  }
}

function transformer(state) {
  return { ...state, count: parseInt(state.count) };
}

function Counter({ initialCount }) {
  const [state, dispatch] = useLocalStorageReducer(
    { reducerKey: "counter", transformer },
    reducer,
    initialState
  );

  return (
    <div>
      Count: {state.count}
      <button onClick={() => dispatch({ type: "reset", payload: initialCount })}>Reset</button>
      <button onClick={() => dispatch({ type: "increment" })}>+</button>
      <button onClick={() => dispatch({ type: "decrement" })}>-</button>
    </div>
  );
}

function App() {
  let name = useLocalStorage("name");
  return (
    <div>
      <h1>{name}</h1>
      <Counter initialCount={0} />
    </div>
  );
}

Not sure about one thing, this won't update the reducerState once it is mounted. Need to investigate that.