fix: Resolve infinite render loop by memoizing context functions and values
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useState, useEffect, createContext, useContext } from "react"
|
||||
import { useState, useEffect, createContext, useContext, useMemo, useCallback } from "react"
|
||||
import { Routes, Route } from "react-router-dom"
|
||||
import { MainLayout } from "./components/layout/MainLayout"
|
||||
import { LoginForm } from "./components/auth/LoginForm"
|
||||
@@ -25,8 +25,15 @@ function AuthProvider({ children }: { children: React.ReactNode }) {
|
||||
const [isAuthenticated, setIsAuthenticated] = useState(false)
|
||||
const [user, setUser] = useState<UserResponse | null>(null)
|
||||
|
||||
const value = useMemo(() => ({
|
||||
isAuthenticated,
|
||||
setIsAuthenticated,
|
||||
user,
|
||||
setUser
|
||||
}), [isAuthenticated, user])
|
||||
|
||||
return (
|
||||
<AuthContext.Provider value={{ isAuthenticated, setIsAuthenticated, user, setUser }}>
|
||||
<AuthContext.Provider value={value}>
|
||||
{children}
|
||||
</AuthContext.Provider>
|
||||
)
|
||||
@@ -81,16 +88,16 @@ function AppContent() {
|
||||
initAuth()
|
||||
}, [setIsAuthenticated, setThemeLocal, setUser])
|
||||
|
||||
const loadHistory = async () => {
|
||||
const loadHistory = useCallback(async () => {
|
||||
try {
|
||||
const history = await ChatService.listConversations()
|
||||
setConversations(history)
|
||||
} catch (err) {
|
||||
console.error("Failed to load conversation history:", err)
|
||||
}
|
||||
}
|
||||
}, [])
|
||||
|
||||
const handleAuthSuccess = async () => {
|
||||
const handleAuthSuccess = useCallback(async () => {
|
||||
try {
|
||||
const userData = await AuthService.getMe()
|
||||
setUser(userData)
|
||||
@@ -102,9 +109,9 @@ function AppContent() {
|
||||
} catch (err: unknown) {
|
||||
console.error("Failed to fetch user profile after login:", err)
|
||||
}
|
||||
}
|
||||
}, [setUser, setIsAuthenticated, setThemeLocal, loadHistory])
|
||||
|
||||
const handleLogout = async () => {
|
||||
const handleLogout = useCallback(async () => {
|
||||
try {
|
||||
await AuthService.logout()
|
||||
} catch (err: unknown) {
|
||||
@@ -117,9 +124,9 @@ function AppContent() {
|
||||
setThreadMessages({})
|
||||
setThemeLocal("light")
|
||||
}
|
||||
}
|
||||
}, [setIsAuthenticated, setUser, setThemeLocal])
|
||||
|
||||
const handleSelectConversation = async (id: string) => {
|
||||
const handleSelectConversation = useCallback(async (id: string) => {
|
||||
setSelectedThreadId(id)
|
||||
try {
|
||||
const msgs = await ChatService.getMessages(id)
|
||||
@@ -127,9 +134,9 @@ function AppContent() {
|
||||
} catch (err) {
|
||||
console.error("Failed to fetch messages:", err)
|
||||
}
|
||||
}
|
||||
}, [])
|
||||
|
||||
const handleCreateConversation = async () => {
|
||||
const handleCreateConversation = useCallback(async () => {
|
||||
try {
|
||||
const newConv = await ChatService.createConversation()
|
||||
setConversations(prev => [newConv, ...prev])
|
||||
@@ -138,18 +145,18 @@ function AppContent() {
|
||||
} catch (err) {
|
||||
console.error("Failed to create conversation:", err)
|
||||
}
|
||||
}
|
||||
}, [])
|
||||
|
||||
const handleRenameConversation = async (id: string, name: string) => {
|
||||
const handleRenameConversation = useCallback(async (id: string, name: string) => {
|
||||
try {
|
||||
const updated = await ChatService.renameConversation(id, name)
|
||||
setConversations(prev => prev.map(c => c.id === id ? updated : c))
|
||||
} catch (err) {
|
||||
console.error("Failed to rename conversation:", err)
|
||||
}
|
||||
}
|
||||
}, [])
|
||||
|
||||
const handleDeleteConversation = async (id: string) => {
|
||||
const handleDeleteConversation = useCallback(async (id: string) => {
|
||||
try {
|
||||
await ChatService.deleteConversation(id)
|
||||
setConversations(prev => prev.filter(c => c.id !== id))
|
||||
@@ -164,11 +171,11 @@ function AppContent() {
|
||||
} catch (err) {
|
||||
console.error("Failed to delete conversation:", err)
|
||||
}
|
||||
}
|
||||
}, [selectedThreadId])
|
||||
|
||||
const handleMessagesFinal = (id: string, messages: MessageResponse[]) => {
|
||||
const handleMessagesFinal = useCallback((id: string, messages: MessageResponse[]) => {
|
||||
setThreadMessages(prev => ({ ...prev, [id]: messages }))
|
||||
}
|
||||
}, [])
|
||||
|
||||
const queryParams = new URLSearchParams(window.location.search)
|
||||
const externalError = queryParams.get("error")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createContext, useContext, useEffect, useState } from "react"
|
||||
import { createContext, useContext, useEffect, useState, useCallback, useMemo } from "react"
|
||||
import { AuthService } from "@/services/auth"
|
||||
|
||||
export type Theme = "light" | "dark"
|
||||
@@ -29,7 +29,7 @@ export function ThemeProvider({
|
||||
root.classList.add(theme)
|
||||
}, [theme])
|
||||
|
||||
const setTheme = async (newTheme: Theme) => {
|
||||
const setTheme = useCallback(async (newTheme: Theme) => {
|
||||
setThemeState(newTheme)
|
||||
if (isAuthenticated) {
|
||||
try {
|
||||
@@ -38,18 +38,25 @@ export function ThemeProvider({
|
||||
console.error("Failed to sync theme to backend:", error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [isAuthenticated])
|
||||
|
||||
const setThemeLocal = (newTheme: Theme) => {
|
||||
const setThemeLocal = useCallback((newTheme: Theme) => {
|
||||
setThemeState(newTheme)
|
||||
}
|
||||
}, [])
|
||||
|
||||
const toggleTheme = () => {
|
||||
const toggleTheme = useCallback(() => {
|
||||
setTheme(theme === "light" ? "dark" : "light")
|
||||
}
|
||||
}, [theme, setTheme])
|
||||
|
||||
const value = useMemo(() => ({
|
||||
theme,
|
||||
setTheme,
|
||||
setThemeLocal,
|
||||
toggleTheme
|
||||
}), [theme, setTheme, setThemeLocal, toggleTheme])
|
||||
|
||||
return (
|
||||
<ThemeContext.Provider value={{ theme, setTheme, setThemeLocal, toggleTheme }}>
|
||||
<ThemeContext.Provider value={value}>
|
||||
{children}
|
||||
</ThemeContext.Provider>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user