【发布时间】:2021-02-02 21:06:23
【问题描述】:
我有一个提供者从服务器接收关于 WebSocket 的通知。
export const MessageProvider: React.FC<ProviderProps> = ({ children }) => {
const [state, dispatch] = useReducer(reducer, messageInitialState);
useEffect(() => {
let cancelled: boolean = false;
__get(cancelled, undefined);
return () => {
cancelled = true;
}
}, []);
useEffect(__wsEffect, []);
const get = useCallback<(cancelled: boolean, userId: number | undefined) => Promise<void>>(__get, []);
const put = useCallback<(message: Message) => Promise<void>>(__put, []);
const value = { ...state, get, put };
return (
<MessageContext.Provider value={value}>
{children}
</MessageContext.Provider>
)
...
function __wsEffect() {
log('{__wsEffect}', 'Connecting');
let cancelled: boolean = false;
const ws = newWebSocket(async (payload) => {
if (cancelled) {
return;
}
const message: Message = payload as Message;
await storageSet(message, __key(message.id));
dispatch({ actionState: ActionState.SUCCEEDED, actionType: ActionType.SAVE, data: message });
});
return () => {
log('{__wsEffect} Disconnecting');
cancelled = true;
ws.close();
}
}
}
然后在我的组件中,我像这样使用这个上下文:
export const MessageListPage: React.FC<RouteComponentProps> = ({ history }) => {
const { data, executing, actionType, actionError, get, put } = useContext(MessageContext);
...
return (
<IonPage id='MessageListPage'>
<IonContent fullscreen>
<IonLoading isOpen={executing && actionType === ActionType.GET} message='Fetching...' />
{
!executing && !actionError && data && (
<div>
<IonList>
{
groupBySender()
.map(__data =>
<div>
<MessageListItem key={__data.sender} sender={__data.sender} messages={__data.messages} />
</div>
)
}
</IonList>
</div>
)
}
</IonContent>
</IonPage>
);
}
然后发生的情况是,每次更新上下文中的data 时,此页面都会重新呈现,从而导致每个MessageListItem 也重新呈现。
问题是我只想重新渲染那些更改可能会影响的 MessageListItem。这可能吗?我想过使用 useMemo 和 memo,但我正在动态创建这些对象,我不知道该怎么做。
这可能吗?
我努力实现以下目标:
user a - x unread messages
user b - y unread messages
...
当我点击一个用户时,我希望该项目展开并显示这些消息。但是当我收到通知时,所有内容都会呈现并且项目恢复为未展开。
【问题讨论】:
标签: reactjs typescript react-hooks react-context