Redux Toolkit Streaming 更新 - 如何处理关系实体适配器?
Redux Toolkit Streaming updates - how to deal with relational entity adapters?
我正在处理使用带有实体适配器的 RTK 查询的聊天。
我目前有 2 个不同的实体适配器;一个用于聊天,一个用于消息。
我怎样才能select发送特定聊天的所有消息?我需要在聊天适配器中存储消息 ID 数组,还是 select 所有消息并按 parent_chat_uuid 属性 过滤它们?
更有效的方法是什么?是否有内置的 selector 允许您通过其 属性 而不是 id 来 select 实体?我想象在非常大的数组上映射以查找具有某些 属性 的对象是非常昂贵的。
谢谢
编辑:
我最初查询最新的聊天记录,一旦 cacheDataLoaded,我就将许多聊天记录添加到实体适配器。
我还设置了 websocket 连接并在数据加载后订阅 'message' 事件。每次消息都由 ws I addOne 消息通知。如果通知 'delivered' 或 'read' 之类的状态,我会调用 updateOne。
我实际上正在尝试重写未使用 RTK 查询和实体适配器的项目,并且消息总是添加到聊天对象内的消息数组中。 Websocket 连接和更新由调用异步 thunk 的中间件处理 -> 更新存储。
我正在尝试移动所有中间件以在 rtk 查询/变异逻辑内部处理并直接从那里调用操作(或者使用更多逻辑调用操作的 thunk)。
** 题外话,我可以为此创建一个单独的 post,但是创建一个仅调用操作的 App Thunk(非异步)有什么好处吗?在这种情况下,我应该只调用操作吗?
我是一名 RTK 维护者,也是 createEntityAdapter
的“作者”(从技术上讲,我从 NgRX 移植了它,但我为此做了很多工作)。
实际上我自己在之前的项目中做过类似的事情。我会把代码的简化版本放到要点中,但我也会 post 在这里 post 也是为了post。
我使用的技术是嵌套实体适配器:一个 top-level 存储聊天室的技术,以及一个嵌套在每个房间条目内的存储该房间消息的技术:
// 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"},
}
}
}
}
}
*/
也就是说,您的情况听起来有些不同,因为您明确表示您正在使用 RTK 查询 和 尝试流式传输某些内容。因此,我实际上不确定您是如何尝试设置端点和存储数据 atm。如果您可以编辑您的 post 更多详细信息然后发表评论,我可以尝试更新此回复以提供更多建议。
具体针对最后一个问题:不,没有 built-in 用于按属性搜索的选择器,这样做通常会变成“re-filter 所有项目只要有更新”。
我正在处理使用带有实体适配器的 RTK 查询的聊天。
我目前有 2 个不同的实体适配器;一个用于聊天,一个用于消息。
我怎样才能select发送特定聊天的所有消息?我需要在聊天适配器中存储消息 ID 数组,还是 select 所有消息并按 parent_chat_uuid 属性 过滤它们?
更有效的方法是什么?是否有内置的 selector 允许您通过其 属性 而不是 id 来 select 实体?我想象在非常大的数组上映射以查找具有某些 属性 的对象是非常昂贵的。
谢谢
编辑:
我最初查询最新的聊天记录,一旦 cacheDataLoaded,我就将许多聊天记录添加到实体适配器。
我还设置了 websocket 连接并在数据加载后订阅 'message' 事件。每次消息都由 ws I addOne 消息通知。如果通知 'delivered' 或 'read' 之类的状态,我会调用 updateOne。
我实际上正在尝试重写未使用 RTK 查询和实体适配器的项目,并且消息总是添加到聊天对象内的消息数组中。 Websocket 连接和更新由调用异步 thunk 的中间件处理 -> 更新存储。
我正在尝试移动所有中间件以在 rtk 查询/变异逻辑内部处理并直接从那里调用操作(或者使用更多逻辑调用操作的 thunk)。
** 题外话,我可以为此创建一个单独的 post,但是创建一个仅调用操作的 App Thunk(非异步)有什么好处吗?在这种情况下,我应该只调用操作吗?
我是一名 RTK 维护者,也是 createEntityAdapter
的“作者”(从技术上讲,我从 NgRX 移植了它,但我为此做了很多工作)。
实际上我自己在之前的项目中做过类似的事情。我会把代码的简化版本放到要点中,但我也会 post 在这里 post 也是为了post。
我使用的技术是嵌套实体适配器:一个 top-level 存储聊天室的技术,以及一个嵌套在每个房间条目内的存储该房间消息的技术:
// 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"},
}
}
}
}
}
*/
也就是说,您的情况听起来有些不同,因为您明确表示您正在使用 RTK 查询 和 尝试流式传输某些内容。因此,我实际上不确定您是如何尝试设置端点和存储数据 atm。如果您可以编辑您的 post 更多详细信息然后发表评论,我可以尝试更新此回复以提供更多建议。
具体针对最后一个问题:不,没有 built-in 用于按属性搜索的选择器,这样做通常会变成“re-filter 所有项目只要有更新”。