使用react-auth-kit的createRefresh钩子时页面重渲染如何解决?
解决react-auth-kit刷新token导致全应用重渲染的问题
问题根源
- refreshApi引用不稳定:每次
App组件渲染时,useRefreshApi都会调用createRefresh生成新的refreshApi实例,导致AuthProvider的refreshprop频繁变化,触发组件树重渲染。 - 组件层级不合理:
AuthProvider嵌套在ContextProvider内部的App组件中,Auth状态更新会连带触发外层组件重新渲染。
解决方案
1. 缓存refreshApi实例,保持引用稳定
修改useRefreshApi,用useMemo包裹createRefresh调用,避免每次渲染生成新实例:
import axios from 'axios' import { createRefresh } from 'react-auth-kit' import { tokenClientId, tokenSecret } from '../config' import { GetCookie } from '../util/cookieManager' import { SSO_USER_DETAILS, REFRESH_SSO_TOKEN } from '../util/constants' import Cookies from 'js-cookie' import { useMemo } from 'react' const useRefreshApi = () => { // 用useMemo缓存refreshApi,仅依赖项变化时重新生成 const refreshApi = useMemo(() => createRefresh({ interval: 4.5, // 每4.5分钟刷新一次token refreshApiCallback: async ({ authToken, authTokenExpireAt, refreshToken, refreshTokenExpiresAt, authUserState }) => { try { const headers = { 'Authorization': 'Basic Auth', 'Content-Type': 'multipart/form-data', } const authAction = axios.create({ headers: headers, auth: { username: tokenClientId, password: tokenSecret } }); const grant = GetCookie('grant'); if(grant === 'password'){ let bodyFormData = new FormData(); bodyFormData.append('grant_type', 'refresh_token'); bodyFormData.append('refresh_token', refreshToken.toString()); const response = await authAction.post('/oauth/token', bodyFormData); return { isSuccess: true, newAuthToken: response.data.access_token, newAuthTokenExpireIn: 5, } } if(grant === 'authorization'){ const headers = { "RefreshToken": refreshToken } const configs = { headers: headers, } const response = await axios.get(REFRESH_SSO_TOKEN, configs) const headers2 = { 'Content-Type': 'application/json', 'Authorization': `Bearer ${response.data.access_token}` } const config = { headers: headers2 } const res = await axios.get(SSO_USER_DETAILS, config) return { isSuccess: true, newAuthToken: res.data.access_token, newAuthTokenExpireIn: 5, } } } catch(error){ Cookies.remove('grant') Cookies.remove('_auth_refresh_time') Cookies.remove('_auth_storage') Cookies.remove('_auth_refresh') Cookies.remove('_auth_state') Cookies.remove('_auth_type') Cookies.remove('_auth') Cookies.set('session_expired', true) } } }), [tokenClientId, tokenSecret]) // 加入依赖项,确保配置变化时重新生成 return { refreshApi } } export default useRefreshApi
2. 调整组件层级,隔离渲染范围
将AuthProvider提升到ContextProvider外层,避免Auth状态变化影响Context相关组件:
修改main.jsx:
import { AuthProvider } from 'react-auth-kit' import useRefreshApi from './path-to-useRefreshApi' const Root = () => { const { refreshApi } = useRefreshApi() return ( <AuthProvider authType={'cookie'} authName={'_auth'} refresh={refreshApi} cookieDomain={window.location.hostname} cookieSecure={window.location.protocol === "https:"} > <StrictMode> <ContextProvider> <App /> </ContextProvider> </StrictMode> </AuthProvider> ) } ReactDOM.createRoot(document.getElementById('root')).render(<Root />)
修改App组件,移除内部的AuthProvider:
function App() { const { note, loaded } = useAppContext() return ( <ThemeProvider theme={theme}> <AppBar position="absolute" color="secondary" elevation={10}> <Toolbar> <Link href="/" sx={{ flexGrow: 1 }}> <Box component="img" sx={{ height: 54}} alt="Logo" src={logo} /> </Link> <Header /> </Toolbar> </AppBar> <Navigation /> <Container > {note && <NotificationContainer />} <Router/> </Container> <AppBar color='primary' /> </ThemeProvider> ) }
3. 优化Context渲染(可选)
检查useAppContext的实现,确保note和loaded仅在必要时更新。可以用useMemo缓存Context提供的状态,或拆分Context为更小粒度,避免无关状态变化触发重渲染。
内容的提问来源于stack exchange,提问作者Lyle Phillips
相关产品推荐
相关产品推荐

