Skip to content

Instantly share code, notes, and snippets.

@markerikson
Last active May 2, 2024 01:27
Show Gist options
  • Save markerikson/ad319fd7b04bd4eecdcfe7bf51dce7b1 to your computer and use it in GitHub Desktop.
Save markerikson/ad319fd7b04bd4eecdcfe7bf51dce7b1 to your computer and use it in GitHub Desktop.
Nested `createEntityAdapter` example
// Example of using multiple / nested `createEntityAdapter` calls within a single Redux Toolkit slice
interface Message {
id: string;
roomId: string;
text: string;
timestamp: string;
username: string;
}
interface ChatRoomEntry {
id: string;
messages: EntityState<Message>;
}
const roomsAdapter = createEntityAdapter<ChatRoomEntry>();
const messagesAdapter = createEntityAdapter<Message>();
const fetchRooms = createAsyncThunk(
"chats/fetchRooms",
chatsAPI.fetchRooms
);
const fetchMessages = createAsyncThunk(
"chats/fetchMessages",
async (roomId) => {
return chatsAPI.fetchMessages(roomId);
}
)
const chatSlice = createSlice({
name: "chats",
initialState: roomsAdapter.getInitialState(),
reducers: {
},
extraReducers: builder => {
builder.addCase(fetchRooms.fulfilled, (state, action) => {
const roomEntries = action.payload.map(room => {
return {id: room.id, messages: messagesAdapter.getInitialState()};
});
roomsAdapter.setAll(state, roomEntries);
})
.addCase(fetchMessages.fulfilled, (state, action) => {
const roomId = action.meta.arg;
const roomEntry = state.entities[roomId];
if (roomEntry) {
messagesAdapter.setAll(roomEntry.messages, action.payload);
}
})
}
})
/*
Resulting state:
{
ids: ["chatRoom1"],
entities: {
chatRoom1: {
id: "chatRoom1",
messages: {
ids: ["message1", "message2"],
entities: {
message1: {id: "message1", text: "hello"},
message2: {id: "message2", text: "yo"},
}
}
}
}
}
*/
@rickysullivan-gallagher

Thanks for the reply, @markerikson. In the words of the great 90s punk rock band, The Offspring, I'm going to Keep 'Em Separated. I like the idea of knowing that each entity has its own home and along with it, auto-generated selectors to boot. Thanks for all your awesome work.

@rickysullivan-gallagher
Copy link

So I decided that I'd try my hand with nesting slices. This way I can keep all my entities reducers/thunks/selectors etc under their own slice, yet keep a top level "entities" slice. But i'm stumped. I can dispatch the actions, and see them working. I just can't workout how to get the slice reducers to combine in the parent slice. https://stackblitz.com/~/github.com/rickysullivan-gallagher/vitejs-vite-ctk89t

@markerikson
Copy link
Author

@rickysullivan-gallagher I'm not actually sure what you're trying to do there, and this gist isn't a great place to provide support :) Could you drop by the #redux channel in the Reactiflux Discord ( https://www.reactiflux.com ) and ask there?

@rickysullivan-gallagher
Copy link

Will do @markerikson. I wasn't feeling confident this was the right place.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment