1.0.6 • Published 2 years ago

@ryfylke-react/create-api-slice v1.0.6

Weekly downloads
-
License
ISC
Repository
github
Last release
2 years ago

@ryfylke-react/create-api-slice

Adds automatic loading state to async thunks. Used as a drop-in replacement for @reduxjs/toolkit's createSlice.

Usage

yarn add @ryfylke-react/create-api-slice
# or
npm i @ryfylke-react/create-api-slice

Create the slice as you normally would, but make sure state is part of your schema. It should take a type of StateStatus. Use our createAPISlice function instead of createSlice from redux toolkit.

slices/postSlice.ts

import {
  createAPISlice,
  StateStatus,
} from "@ryfylke-react/create-api-slice";

const initialState = {
  ...baseInitialState,
  state: StateStatus.IDLE,
};

const postSlice = createAPISlice({
  name: "post",
  initialState,
  reducers: {},
  extraReducers: (builder) => {
    builder
      .addCase(getPost.fulfilled, (state, { payload }) => {
        state.post = payload;
      })
      .addCase(getPost.rejected, (state) => {
        state.post = null;
      });
  },
});

export const postReducer = postSlice.reducer;

Then, when you create thunks that require loading state, make sure to append :load to the thunk name.

slices/postThunks.ts

export const getPost = createAsyncThunk(
  `post/getPost:load`,
  async (slug: string, { rejectWithValue }) => {
    return axios
      .get<PostData[]>(`${API_URL}/posts?slug=${slug}`)
      .then((res) => res.data[0])
      .catch((err) => rejectWithValue(err));
  }
);

Calling dispatch(getPost("...")) will now automatically set the loading state to 1 (PENDING), which will again automatically change to 2 (FULFILLED) or 3 (REJECTED).

Here's how you'd implement this logic on the UI:

// ...
import { StateStatus } from "@ryfylke-react/create-api-slice";

const App = () => {
    const { id } = useParams();
    const dispatch = useDispatch();
    const { state, post } = useSelector((state) => state.post);

    useEffect(() => {
        dispatch(getPost(id));
    }, []);

    if (state === StateStatus.REJECTED) {
        return "Error from server";
    }
    if (state === StateStatus.FULFILLED) {
        return (...);
    }
    return "Loading...";
}

This unfortunately only supports one concurring loading state per slice. This means that if you call two async thunks that both have :load appended - they will both mutate the same loading state.

Options

If you want, you can add a second parameter to createAPISlice, which is an options object of type APISliceOpts:

type APISliceOpts<T> = {
  /** The key that stores the StateStatus in the slice. Default `state`. */
  key?: string;
  /** The identifier used to add loading state. Default `:load` */
  identifier?: string;
  /** Replaces the createSlice function used internally */
  createSliceOverwrite?: (
    options: CreateSliceOptions<T, SliceCaseReducers<T>, string>
  ) => any;
};
1.0.6

2 years ago

1.0.5

2 years ago

1.0.4

2 years ago

1.0.3

2 years ago

1.0.2

2 years ago

1.0.1

2 years ago

1.0.0

2 years ago