UNPKG

cra-template-bod

Version:

The advanced TypeScript template for Bod CLI.

93 lines (85 loc) 3.23 kB
import type { PayloadAction } from '@reduxjs/toolkit' import type { AppThunk } from '../../store' import { createAppSlice } from '../../utils/redux-utils' import { fetchCount } from './service' export interface CounterState { value: number status: 'idle' | 'loading' | 'failed' } const initialState: CounterState = { value: 0, status: 'idle', } // If you are not using async thunks you can use the standalone `createSlice`. export const counterSlice = createAppSlice({ name: 'counter', // `createSlice` will infer the state type from the `initialState` argument initialState, // The `reducers` field lets us define reducers and generate associated actions reducers: create => ({ increment: create.reducer((state) => { // Redux Toolkit allows us to write "mutating" logic in reducers. It // doesn't actually mutate the state because it uses the Immer library, // which detects changes to a "draft state" and produces a brand new // immutable state based off those changes state.value += 1 }), decrement: create.reducer((state) => { state.value -= 1 }), // Use the `PayloadAction` type to declare the contents of `action.payload` incrementByAmount: create.reducer( (state, action: PayloadAction<number>) => { state.value += action.payload }, ), // The function below is called a thunk and allows us to perform async logic. It // can be dispatched like a regular action: `dispatch(incrementAsync(10))`. This // will call the thunk with the `dispatch` function as the first argument. Async // code can then be executed and other actions can be dispatched. Thunks are // typically used to make async requests. incrementAsync: create.asyncThunk( async (amount: number) => { const response = await fetchCount(amount) // The value we return becomes the `fulfilled` action payload return response.data }, { pending(state) { state.status = 'loading' }, fulfilled(state, action) { state.status = 'idle' state.value += action.payload }, rejected(state) { state.status = 'failed' }, }, ), }), // You can define your selectors here. These selectors receive the slice // state as their first argument. selectors: { selectCount: counter => counter.value, }, }) // Action creators are generated for each case reducer function. export const { decrement, increment, incrementByAmount, incrementAsync } = counterSlice.actions // Selectors returned by `slice.selectors` take the root state as their first argument. export const { selectCount } = counterSlice.selectors /** * We can also write thunks by hand, which may contain both sync and async logic. * Here's an example of conditionally dispatching actions based on current state. * @param {number} amount amount * @returns {AppThunk} AppThunk */ export function incrementIfOdd(amount: number): AppThunk { return (dispatch, getState) => { const currentValue = selectCount(getState()) if (currentValue % 2 === 1 || currentValue % 2 === -1) { dispatch(incrementByAmount(amount)) } } }