redux toolkit upsert one

Have you ever heard of the term "upsert"? It means "create, or update if one is already created". That's right, two operations, one function. And redux toolkit has a way to do that.

In our toy app over in the browser panel, you can play around with this. Create a new mission, and see it appear in the rows. Edit an existing mission, and see it get updated. Amazing!

So how does this magic work? Well, if I can direct your attention to missionsSlice.js, you'll see that we are now adding an "upsert" key in our reducers object in the createSlice call. Inside here, we're going to use our missionsAdapter's upsertOnefunction. We're declaring an inline reducer here, reducers always take the arguments state, action which refer to the global state, and the action object. Actions have a payload key, which is the data we want to upsert. So the upsertOne function requires us to pass in the state and the data, and that's all there is to it.

Using this reducer requires us to dispatch an action. How do we get this action? Well, we can find the actions from the missionsSlice.actions object, declared at the bottom of missionsSlice.js. Here, we destructure off upsert and call it upsertMission so we can use it in our app.

To use the action, we need a special hook called useDispatch from react-redux. You can think of this as "writing data" and the useSelector as "reading data".

Updating our data is as easy as calling dispatch(upsertMission( [new mission object])). We're upserting the mission with the current mission object, but with the new title and description merged onto it.

NewMission.js also dispatches an upsertMission action, but with a random id, and new attributes as we're creating a new mission object here.

That's it. Now, we can be confident that our updates are flowing nicely throughout our app- once we update a mission, we can go view it on the Missions route, as our selector will automatically pick up on the update.

Next, we'll do a similar pattern but for deleting data.

Menu
Lesson 5/6
import { createSlice, createEntityAdapter } from "@reduxjs/toolkit";
import defaultMissions from "./missionData";

const missionsAdapter = createEntityAdapter();

const emptyInitialState = missionsAdapter.getInitialState();
const initialState = missionsAdapter.upsertMany(
  emptyInitialState,
  defaultMissions
);

const missionsSlice = createSlice({
  name: "missions",
  initialState,
  reducers: {
    upsert: (state, action) => missionsAdapter.upsertOne(state, action.payload),
  },
});

export const { selectAll: selectAllMissions, selectById: selectMissionById } =
  missionsAdapter.getSelectors((state) => state.missions);

export const { upsert: upsertMission } = missionsSlice.actions;

export default missionsSlice.reducer;