From e1d685d24b77250b4cea833ac043d10e9839342a Mon Sep 17 00:00:00 2001 From: Adrian <107351903+6lr61@users.noreply.github.com> Date: Fri, 13 Sep 2024 10:50:32 +0200 Subject: [PATCH] feat: useGetProfile hook instead of the UserProfileContext the hook will return an initial value, which may be undefined, but update it later the profiles are stored in a global variable, so all calls to the hook share the same user profiles --- src/App.tsx | 11 +---- .../{MessageContainer.tsx => Chat.tsx} | 18 +++---- src/components/Message.tsx | 39 +++++++-------- src/components/ProfilePicture.tsx | 17 ++++--- src/contexts/UserProfileContext.ts | 4 -- src/contexts/UserProfileProvider.tsx | 48 ------------------- src/hooks/useGetProfile.ts | 35 ++++++++++++++ 7 files changed, 75 insertions(+), 97 deletions(-) rename src/components/{MessageContainer.tsx => Chat.tsx} (55%) delete mode 100644 src/contexts/UserProfileContext.ts delete mode 100644 src/contexts/UserProfileProvider.tsx create mode 100644 src/hooks/useGetProfile.ts diff --git a/src/App.tsx b/src/App.tsx index 7de53bf..f535ef3 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,13 +1,10 @@ import { useContext } from "react"; import { AuthStateContext } from "./contexts/auth-state/AuthStateContext"; import LoginButton from "./components/LoginButton"; -import { useTwitchChat } from "./hooks/useTwitchChat"; -import Message from "./components/Message"; -import MessageContainer from "./components/MessageContainer"; +import Chat from "./components/Chat"; export default function App() { const authContext = useContext(AuthStateContext); - const messages = useTwitchChat(); if (!authContext) { return

Missing AuthStateContext provider?

; @@ -23,11 +20,7 @@ export default function App() {

Chat Messages:

- - {messages.map((message) => ( - - ))} - +
)} diff --git a/src/components/MessageContainer.tsx b/src/components/Chat.tsx similarity index 55% rename from src/components/MessageContainer.tsx rename to src/components/Chat.tsx index b181598..837cb29 100644 --- a/src/components/MessageContainer.tsx +++ b/src/components/Chat.tsx @@ -1,14 +1,10 @@ import { useEffect, useRef } from "react"; -import type { ChatMessage } from "../hooks/useTwitchChat"; import TwitchBadgeProvider from "../contexts/badges/TwitchBadgeProvider"; +import { useTwitchChat } from "../hooks/useTwitchChat"; +import Message from "./Message"; -export default function MessageContainer({ - children, - messages, -}: { - children: React.ReactNode; - messages: ChatMessage[]; -}): React.ReactElement { +export default function Chat(): React.ReactElement { + const messages = useTwitchChat(); const ref = useRef(null); useEffect(() => { @@ -22,7 +18,11 @@ export default function MessageContainer({ return (
-
{children}
+
+ {messages.map((message) => ( + + ))} +
); diff --git a/src/components/Message.tsx b/src/components/Message.tsx index a79faa3..2bab48a 100644 --- a/src/components/Message.tsx +++ b/src/components/Message.tsx @@ -8,7 +8,6 @@ import Reply from "./Reply"; import TextSegment from "./TextSegment"; import TwitchEmote from "./TwitchEmote"; import UserName from "./UserName"; -import UserProfileProvider from "../contexts/UserProfileProvider"; interface Props { message: ChatMessage; @@ -47,26 +46,24 @@ function fragmentToComponent( export default function Message({ message }: Props): React.ReactElement { return ( - -
- -
-
- - - -
- {message.reply && } -
- {message.message.fragments.map((fragment, index) => - fragmentToComponent(fragment, index) - )} -
+
+ +
+
+ + + +
+ {message.reply && } +
+ {message.message.fragments.map((fragment, index) => + fragmentToComponent(fragment, index) + )}
-
- +
+
); } diff --git a/src/components/ProfilePicture.tsx b/src/components/ProfilePicture.tsx index b5b3244..8313212 100644 --- a/src/components/ProfilePicture.tsx +++ b/src/components/ProfilePicture.tsx @@ -1,13 +1,18 @@ -import { useContext } from "react"; -import { UserProfileContext } from "../contexts/UserProfileContext"; +import { useGetProfile } from "../hooks/useGetProfile"; -export default function ProfilePicture(): React.ReactElement { - const userData = useContext(UserProfileContext); +export default function ProfilePicture({ + login, +}: { + login: string; +}): React.ReactElement { + const userData = useGetProfile(login); return ( -
- {userData?.profile_image_url && ( +
+ {userData?.profile_image_url ? ( + ) : ( +
)}
); diff --git a/src/contexts/UserProfileContext.ts b/src/contexts/UserProfileContext.ts deleted file mode 100644 index 079e85e..0000000 --- a/src/contexts/UserProfileContext.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { createContext } from "react"; -import type { UserData } from "../utils/api/getUser"; - -export const UserProfileContext = createContext(null); diff --git a/src/contexts/UserProfileProvider.tsx b/src/contexts/UserProfileProvider.tsx deleted file mode 100644 index 247a2e4..0000000 --- a/src/contexts/UserProfileProvider.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { useContext, useEffect, useState } from "react"; -import { UserProfileContext } from "./UserProfileContext"; -import { AuthStateContext } from "./auth-state/AuthStateContext"; -import { getUser, type UserData } from "../utils/api/getUser"; - -interface UserProfileProviderProps { - children: React.ReactNode; - login?: string; -} - -export default function UserProfileProvider({ - children, - login, -}: UserProfileProviderProps): React.ReactElement { - const authStateContext = useContext(AuthStateContext); - const authState = authStateContext?.authState; - const [userData, setUserData] = useState(null); - - useEffect(() => { - let keep = true; - - if (authState) { - getUser( - authState.token.value, - authState.client.id, - login ?? authState.user.login - ) - .then((data) => { - if (keep) { - setUserData(data); - } - }) - .catch((error: unknown) => { - console.error("UserProfile:", error); - }); - } - - return () => { - keep = false; - }; - }, [authState, login]); - - return ( - - {children} - - ); -} diff --git a/src/hooks/useGetProfile.ts b/src/hooks/useGetProfile.ts new file mode 100644 index 0000000..8dbd1e7 --- /dev/null +++ b/src/hooks/useGetProfile.ts @@ -0,0 +1,35 @@ +import { useContext, useEffect, useState } from "react"; +import { AuthStateContext } from "../contexts/auth-state/AuthStateContext"; +import { getUser, type UserData } from "../utils/api/getUser"; + +const usersData = new Map(); + +export function useGetProfile(login: string) { + const authStateContext = useContext(AuthStateContext); + const authState = authStateContext?.authState; + + const [userProfile, setUserProfile] = useState(() => + usersData.get(login) + ); + + useEffect(() => { + if (usersData.has(login)) { + return; + } + + if (!authState) { + return; + } + + getUser(authState.token.value, authState.client.id, login) + .then((data) => { + usersData.set(login, data); + setUserProfile(() => data); + }) + .catch((error: unknown) => { + console.error("UserProfile:", error); + }); + }, [authState, login]); + + return userProfile; +}