wand3r / teasy-redux

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

TeaSy Redux

Utility functions for boilerplate free Redux with TypeScript

Presentation

Installation

yarn add teasy-redux

or

npm i teasy-redux

Usage

Action Creators

const addTodo = createAction(
  "ADD_TODO",
  payload((text: string) => ({
    id: Math.random(),
    text,
  })),
)

addTodo("text")

const actions = createActions({
  addTodo: payload((text: string) => ({
    id: Math.random(),
    text,
  })),
  editTodo: payload<{ id: number; text: string }>(),
  removeTodo: (id: number) => ({ payload: { id } }),
})

actions.addTodo("New text")
actions.editTodo({ id: 123, text: "Edited text" })
actions.removeTodo(123)

Reducers

createReducer

  • shows TS error when not all actions are handled
  • makes state deep readonly in all handlers to prevent accidental mutation
  • handles default case automatically by returning unchanged state
  • allows specifying own default handler
type State = { id: number; text: string }[]

const reducer = createReducer<State, typeof actions>(
  {
    addTodo: (todos, { payload: { id, text } }) => {
      return todos
    },
    editTodo: (todos, { payload: { id, text } }) => {
      return todos
    },
    removeTodo: (todos, { payload: { id } }) => {
      return todos
    },
  },
  [],
)

const reducer = (todos: State, action: ActionUnion<typeof actions>): State => {
  switch (action.type) {
    case actions.addTodo.type: {
      const { id, text } = action.payload
      return todos
    }
    case actions.editTodo.type: {
      const { id, text } = action.payload
      return todos
    }
    case actions.removeTodo.type: {
      const { id } = action.payload
      return todos
    }
    default: {
      return todos
    }
  }
}

Type Guards

if (is(anyAction, actions.addTodo)) {
  // ...
}
if (is(anyAction, [actions.addTodo, actions.editTodo])) {
  // ...
}
if (is(anyAction, actions)) {
  // ...
}

Action Union

const actionsArr = [actions.addTodo, actions.removeTodo]

type Union1 = ActionUnion<typeof actions>
type Union2 = ActionUnion<typeof actionsArr>

Usage with useReducer Hook

CodeSandbox

const actions = createActions({
  increment: payload<{ by: number }>(),
  decrement: payload<{ by: number }>(),
})

type State = { count: number }

const initialState: State = { count: 0 }

const reducer = createReducer<State, typeof actions>(
  {
    increment: (state, { payload: { by } }) => {
      return { count: state.count + by }
    },
    decrement: (state, { payload: { by } }) => {
      return { count: state.count - by }
    },
  },
  initialState,
)

export const Counter: FC = () => {
  const [state, dispatch] = useReducer(reducer, initialState)
  return (
    <div>
      <button onClick={() => dispatch(actions.decrement({ by: 2 }))}>-</button>>
      <span>{state.count}</span>
      <button onClick={() => dispatch(actions.increment({ by: 2 }))}>+</button>
    </div>
  )
}

Prior work

About


Languages

Language:TypeScript 98.4%Language:JavaScript 1.6%