We can use Redux without Redux.
Tags: react, redux, javascript
Published: 2019-02-16 08:16:35

---
title: We can use Redux without Redux.
published: true
description: 
tags: React,Redux,JavaScript
---

We can manage state like Redux without Redux with addition new feature "Hooks".

## useReducer + Context

- First, define the reducer like Redux.
- Second, create the Context that manages state and dispatch.
- Third, create state and reducer with `useReducer` and pass those to `StoreContext.Provider`.
- Finaly, access to state or dispatch with `useContext` (or, `StoreContext.Consumer`).

```tsx
import * as React from "react";
import * as ReactDOM from "react-dom";

type State = { count: number };
type Action = { type: "increment" | "decrement" | "reset" };
const initialState: State = { count: 0 };

function reducer(state: CounterState, action: Action): State {
  case "reset": {
    return initialState;
  }
  case "increment": {
    return { count: state.count + 1 };
  }
  case "decrement": {
    return { count: state.count - 1 };
  }
  default: {
    return state;
  }
}

const StoreContext = React.createContext<{
  state: State,
  dispatch: React.Dispatch<Action>
}>({state: null as any, dispatch: null as any});

function App() {
  const [state, dispatch] = React.useReducer(reducer, initialState);
  return (
    <StoreContext value={{ state, dispatch }}>
      <Counter />
    </StoreContext>
  )
}

function Counter() {
  const { state, dispatch } = React.useContext(StoreContext);
  return (
    <>
      <p>{state.count}</p>
      <button onClick={() => dispatch({ type: "reset" })}>reset</button>
      <button onClick={() => dispatch({ type: "increment" })}>+</button>
      <button onClick={() => dispatch({ type: "decrement" })}>-</button>
    </>
  )
}

ReactDOM.render(<App />, document.querySelector("#root"));
```

I like this pattern! This is useful for small project. We should use Redux only we want to use middlewares.

## reducer-context-hook

I published a library named `reducer-context-hook` (GitHub: https://github.com/sosukesuzuki/reducer-context-hook ). This library wraps the above pattern.

`reducer-context-hook` exports a function named `create()`. `create()` function returns a object contains `StoreContextProvider`, `useMappedState` and `useDispatch`.

```ts
import create from "reducer-context-hook";

export const { StoreContextProvider, useDispatch, useMappedState } = create<
  State,
  Action
>();
```

### StoreContextProvider

`StoreContextProvider` has same role as `StoreContext.Provider` in the above pattern. Please use like below:

```tsx
function App() {
  return (
    <StoreContextProvider reducer={reducer} initialState={initialState}>
      <Counter />
    </StoreContextProvider>
  );
}
```

### useMappedState

`useMappedState` has same role `connect` in `react-redux`. (only state). It recieves two arguments.The first is `mapState` function.The second is `memoizationArray`.`memoizationArray` is used to memoize like `useCallback`. (`useCallback` beeing used in `useMappedState` to memoize function.) Please use like below:

```tsx
function Counter() {
  const { count } = useMappedState(
    state => ({
      count: state.count
    }),
    []
  );
  return <p>{count}</p>;
}
```

### useDispatch

`useDispatch` returns `dispatch`.We can use action with it. Please use like below:

```tsx
function Increment() {
  const dispatch = useDispatch();
  const increment = React.useCallback(
    () => dispatch({ type: "increment" }),
    []
  );
  return <button onClick={increment}>+</button>;
}
```