You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用react-auth-kit的createRefresh钩子时页面重渲染如何解决?

解决react-auth-kit刷新token导致全应用重渲染的问题

问题根源

  1. refreshApi引用不稳定:每次App组件渲染时,useRefreshApi都会调用createRefresh生成新的refreshApi实例,导致AuthProvider的refresh prop频繁变化,触发组件树重渲染。
  2. 组件层级不合理: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 21:20:40