6
\$\begingroup\$

I've just taken the leap over to RTK instead of 'vanilla' redux and am blown away by how much less code I need to write. I'm not entirely sure how to structure my slices, however, and figured I'd ask for a small code review so I do not accidentally start breaking conventions from the start. This is how one of my slices is currently looking:

import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit';
import bundle from '../../bundler';
import {BundleStartAction, BundleCompleteAction, BundlesState } from './bundleSliceInterface.ts'
export const createBundle = createAsyncThunk(
 'bundle',
 async (data: { cellId: string; input: string }, thunkAPI) => {
 const { cellId, input } = data;
 thunkAPI.dispatch(bundleStart({ cellId }));
 const result = await bundle(input);
 thunkAPI.dispatch(
 bundleComplete({ cellId, bundle: { code: result.code, err: result.err } })
 );
 }
);
const initialState: BundlesState = {};
const bundleSlice = createSlice({
 name: 'bundle',
 initialState,
 reducers: {
 bundleStart: (state, action: PayloadAction<BundleStartAction>) => {
 state[action.payload.cellId] = { loading: true, code: '', err: '' };
 },
 bundleComplete: (state, action: PayloadAction<BundleCompleteAction>) => {
 state[action.payload.cellId] = {
 loading: false,
 code: action.payload.bundle.code,
 err: action.payload.bundle.err,
 };
 },
 },
 extraReducers: {},
});
export const { bundleStart, bundleComplete } = bundleSlice.actions;
export default bundleSlice.reducer;

Any feedback or tips on how to structure slices properly is greatly appreciated.

Thanks in advance!

asked Mar 27, 2021 at 21:09
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

I am blown away by how much less code I need to write

I'm going to blow your mind even more because you actually do not need to dispatch any actions inside createAsyncThunk. It does that for you!

The "pending" action doesn't have a payload so getting the cellId is a little bit tricky. You can see the types of the dispatched actions in the docs. The property that you want is action.meta.arg.cellId.

You get better TypeScript support on your reducer by using the builder callback notation. It already knows the types of your thunk actions!

The part that I am unclear on is what your bundle function does as it seems like it catches errors on its own? That's fine but you can also throw errors in the inner function of createAsyncThunk and handle them in the reducer with the createBundle.rejected action. You can also use the rejectWithValue helper to customize the error payload.

export const createBundle = createAsyncThunk(
 "bundle/create",
 async (data: { cellId: string; input: string }) => {
 const { cellId, input } = data;
 const result = await bundle(input);
 // this is the payload
 return {
 cellId,
 bundle: result
 };
 }
);
const initialState: BundlesState = {};
const bundleSlice = createSlice({
 name: "bundle",
 initialState,
 reducers: {},
 extraReducers: (builder) =>
 builder
 .addCase(createBundle.pending, (state, action) => {
 const { cellId } = action.meta.arg;
 state[cellId] = { loading: true, code: "", err: "" };
 })
 .addCase(createBundle.rejected, (state, action) => {
 //??
 })
 .addCase(createBundle.fulfilled, (state, action) => {
 const { bundle, cellId } = action.payload;
 state[cellId] = {
 loading: false,
 code: bundle.code,
 err: bundle.err
 };
 })
});
answered Apr 23, 2021 at 2:15
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.