Skip to content

Instantly share code, notes, and snippets.

@HansKre
Last active January 2, 2024 08:22
Show Gist options
  • Save HansKre/10a94d3917c68cf1b386096550cd5008 to your computer and use it in GitHub Desktop.
Save HansKre/10a94d3917c68cf1b386096550cd5008 to your computer and use it in GitHub Desktop.
redux-toolkit

asyncThunk

https://redux-toolkit.js.org/usage/usage-with-typescript

https://redux-toolkit.js.org/usage/usage-with-typescript#typing-async-thunks-inside-createslice

A type for state and/or dispatch cannot be provided as part of the ThunkApiConfig, as this would cause circular types.

const state = thunkApi.getState() as RootState;
const dispatch = thunkApi.dispatch as AppDispatch;

Example with buildCreateSlice

import { asyncThunkCreator, buildCreateSlice } from '@reduxjs/toolkit';
import { AppDispatch } from './store';

type State = {
  title: string;
  infoMessages: Array<string>;
  open: boolean;
  onClose: () => void;
  disableActions?: boolean;
};

const noop = () => {};

const initialState: State = {
  infoMessages: [],
  open: false,
  onClose: noop,
  title: '',
  disableActions: false,
};

const createSliceWithThunks = buildCreateSlice({
  creators: { asyncThunk: asyncThunkCreator },
});

export const infoDialogSlice = createSliceWithThunks({
  initialState,
  name: 'infoDialog',
  reducers: (create) => ({
    closeInfoDialog: create.reducer(() => {
      return {
        open: false,
        infoMessages: [],
        onClose: noop,
        title: '',
        disableActions: false,
      };
    }),
    openInfoDialog: create.asyncThunk<
      Omit<StatewithOptionalOnClose, 'open'>,
      State
    >(
      (payload, thunkApi): State => {
        const dispatch = thunkApi.dispatch as AppDispatch;
        const {
          infoMessages,
          onClose = () => dispatch(closeInfoDialog()),
          title,
          disableActions = false,
        } = payload;
        return { open: true, infoMessages, onClose, title, disableActions };
      },
      {
        fulfilled: (_, action) => {
          return action.payload;
        },
      }
    ),
  }),
});

// State with optional "onClose" property
type StatewithOptionalOnClose = Omit<State, 'onClose'> &
  Partial<Pick<State, 'onClose'>>;

export const { openInfoDialog, closeInfoDialog } = infoDialogSlice.actions;

Example with basic createSlite and extraReducers

import { PayloadAction, createAsyncThunk, createSlice } from '@reduxjs/toolkit';
import { AppDispatch } from './store';

type State = {
  title: string;
  infoMessages: Array<string>;
  open: boolean;
  onClose: () => void;
  disableActions?: boolean;
};

const noop = () => {};

const initialState: State = {
  infoMessages: [],
  open: false,
  onClose: noop,
  title: '',
  disableActions: false,
};

export const infoDialogSlice = createSlice({
  initialState,
  name: 'infoDialog',
  reducers: {
    openInfoDialog: (_, action: PayloadAction<Omit<State, 'open'>>) => {
      const {
        infoMessages,
        onClose,
        title,
        disableActions = false,
      } = action.payload;
      return { open: true, infoMessages, onClose, title, disableActions };
    },
    closeInfoDialog: () => {
      return {
        open: false,
        infoMessages: [],
        onClose: noop,
        title: '',
        disableActions: false,
      };
    },
  },
  extraReducers: (builder) => {
    builder.addCase(
      openInfoDialog.fulfilled,
      (_, action: PayloadAction<State>) => {
        return action.payload;
      }
    );
  },
});

// State with optional "onClose" property
type StatewithOptionalOnClose = Omit<State, 'onClose'> &
  Partial<Pick<State, 'onClose'>>;

export const openInfoDialog = createAsyncThunk<
  State,
  Omit<StatewithOptionalOnClose, 'open'>,
  { dispatch: AppDispatch }
>('infoDialog/openInfoDialog', (payload, { dispatch }) => {
  const {
    infoMessages,
    onClose = () => dispatch(closeInfoDialog()),
    title,
    disableActions = false,
  } = payload;
  return { open: true, infoMessages, onClose, title, disableActions };
});

export const { closeInfoDialog } = infoDialogSlice.actions;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment