From bb88176b728ce06861834681a8571cc49dffb681 Mon Sep 17 00:00:00 2001 From: moonrailgun Date: Tue, 13 Jul 2021 17:51:23 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E7=BC=93=E5=AD=98=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E4=B8=8Eredux=E5=A2=9E=E5=8A=A0=E5=A5=BD=E5=8F=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- shared/api/socket.ts | 2 +- shared/cache/Provider.tsx | 15 +++++++++++++++ shared/cache/cache.ts | 20 ++++++++++++++++++++ shared/cache/index.ts | 5 +++++ shared/{hooks => cache}/useCache.ts | 4 ++-- shared/components/Provider.tsx | 10 ++-------- shared/index.tsx | 5 ++++- shared/redux/setup.ts | 11 +++++++++++ shared/redux/slices/user.ts | 7 +++++++ web/src/components/UserListItem.tsx | 4 ++-- 10 files changed, 69 insertions(+), 14 deletions(-) create mode 100644 shared/cache/Provider.tsx create mode 100644 shared/cache/cache.ts create mode 100644 shared/cache/index.ts rename shared/{hooks => cache}/useCache.ts (76%) diff --git a/shared/api/socket.ts b/shared/api/socket.ts index 05ad161c..4d864634 100644 --- a/shared/api/socket.ts +++ b/shared/api/socket.ts @@ -44,7 +44,7 @@ export class AppSocket { }); } - listen(eventName: string, callback: (data: unknown) => void) { + listen(eventName: string, callback: (data: T) => void) { this.socket.on(`notify:${eventName}`, callback); } } diff --git a/shared/cache/Provider.tsx b/shared/cache/Provider.tsx new file mode 100644 index 00000000..ec4a574b --- /dev/null +++ b/shared/cache/Provider.tsx @@ -0,0 +1,15 @@ +import React from 'react'; +import { QueryClientProvider } from 'react-query'; +import { queryClient } from './'; + +/** + * 缓存上下文 + */ +export const CacheProvider: React.FC = React.memo((props) => { + return ( + + {props.children} + + ); +}); +CacheProvider.displayName = 'CacheProvider'; diff --git a/shared/cache/cache.ts b/shared/cache/cache.ts new file mode 100644 index 00000000..edd0381b --- /dev/null +++ b/shared/cache/cache.ts @@ -0,0 +1,20 @@ +import { fetchUserInfo, UserBaseInfo } from '../model/user'; +import { queryClient } from './index'; + +function buildCacheFactory( + scope: string, + fetcher: (id: string) => Promise +) { + return async (id: string): Promise => { + const data = await queryClient.fetchQuery([scope, id], () => fetcher(id)); + return data; + }; +} + +/** + * 获取缓存的用户信息 + */ +export const getCachedUserInfo = buildCacheFactory( + 'user', + fetchUserInfo +); diff --git a/shared/cache/index.ts b/shared/cache/index.ts new file mode 100644 index 00000000..2f31459d --- /dev/null +++ b/shared/cache/index.ts @@ -0,0 +1,5 @@ +import { QueryClient } from 'react-query'; + +const queryClient = new QueryClient(); + +export { queryClient }; diff --git a/shared/hooks/useCache.ts b/shared/cache/useCache.ts similarity index 76% rename from shared/hooks/useCache.ts rename to shared/cache/useCache.ts index 38d23614..9e75ea14 100644 --- a/shared/hooks/useCache.ts +++ b/shared/cache/useCache.ts @@ -1,7 +1,7 @@ import { useQuery } from 'react-query'; import { fetchUserInfo, UserBaseInfo } from '../model/user'; -function buildCacheFactory( +function buildUseCacheFactory( scope: string, fetcher: (id: string) => Promise ) { @@ -11,7 +11,7 @@ function buildCacheFactory( }; } -export const useUserInfo = buildCacheFactory( +export const useCachedUserInfo = buildUseCacheFactory( 'user', fetchUserInfo ); diff --git a/shared/components/Provider.tsx b/shared/components/Provider.tsx index fb8fd7a6..fcdeae45 100644 --- a/shared/components/Provider.tsx +++ b/shared/components/Provider.tsx @@ -1,13 +1,7 @@ import React from 'react'; -import { QueryClient, QueryClientProvider } from 'react-query'; - -const queryClient = new QueryClient(); +import { CacheProvider } from '../cache/Provider'; export const PawProvider: React.FC = React.memo((props) => { - return ( - - {props.children} - - ); + return {props.children}; }); PawProvider.displayName = 'PawProvider'; diff --git a/shared/index.tsx b/shared/index.tsx index 41d761ce..1d64a2b4 100644 --- a/shared/index.tsx +++ b/shared/index.tsx @@ -3,6 +3,10 @@ export { buildStorage } from './api/buildStorage'; export { createSocket } from './api/socket'; export type { AppSocket } from './api/socket'; +// cache +export { getCachedUserInfo } from './cache/cache'; +export { useCachedUserInfo } from './cache/useCache'; + // components export { FastForm } from './components/FastForm/index'; export { CustomField } from './components/FastForm/CustomField'; @@ -23,7 +27,6 @@ export { t, setLanguage, useTranslation } from './i18n'; export { useAsync } from './hooks/useAsync'; export { useAsyncFn } from './hooks/useAsyncFn'; export { useAsyncRequest } from './hooks/useAsyncRequest'; -export { useUserInfo } from './hooks/useCache'; export { useMountedState } from './hooks/useMountedState'; export { useRafState } from './hooks/useRafState'; diff --git a/shared/redux/setup.ts b/shared/redux/setup.ts index 6ae6b093..54616f6e 100644 --- a/shared/redux/setup.ts +++ b/shared/redux/setup.ts @@ -3,6 +3,7 @@ import type { AppSocket } from '../api/socket'; import { userActions } from './slices'; import type { UserBaseInfo } from '../model/user'; import type { FriendRequest } from '../model/friend'; +import { getCachedUserInfo } from '../cache/cache'; /** * 初始化Redux 上下文 @@ -17,4 +18,14 @@ export function setupRedux(socket: AppSocket, store: AppStore) { socket.request('friend.request.allRelated').then((data) => { store.dispatch(userActions.setFriendRequests(data)); }); + + socket.listen<{ userId: string }>('friend.add', ({ userId }) => { + if (typeof userId !== 'string') { + console.error('错误的信息', userId); + return; + } + getCachedUserInfo(userId).then((info) => { + store.dispatch(userActions.appendFriend(info)); + }); + }); } diff --git a/shared/redux/slices/user.ts b/shared/redux/slices/user.ts index 969e1d67..788532d2 100644 --- a/shared/redux/slices/user.ts +++ b/shared/redux/slices/user.ts @@ -26,6 +26,13 @@ const userSlice = createSlice({ setFriendRequests(state, action: PayloadAction) { state.friendRequests = action.payload; }, + appendFriend(state, action: PayloadAction) { + if (state.friends.some(({ _id }) => _id === action.payload._id)) { + return; + } + + state.friends.push(action.payload); + }, }, }); diff --git a/web/src/components/UserListItem.tsx b/web/src/components/UserListItem.tsx index 2b6bf1c8..678a9802 100644 --- a/web/src/components/UserListItem.tsx +++ b/web/src/components/UserListItem.tsx @@ -3,7 +3,7 @@ import { Avatar } from './Avatar'; import _isNil from 'lodash/isNil'; import { Skeleton, Space } from 'antd'; // import { openUserProfile } from './modals/UserProfile'; -import { useUserInfo } from 'pawchat-shared'; +import { useCachedUserInfo } from 'pawchat-shared'; // const UserAvatar = styled(Avatar)` // cursor: pointer !important; @@ -21,7 +21,7 @@ interface UserListItemProps { } export const UserListItem: React.FC = React.memo((props) => { const { actions = [] } = props; - const userInfo = useUserInfo(props.userId); + const userInfo = useCachedUserInfo(props.userId); const userName = userInfo.nickname; const handleClick = useCallback(() => {