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

React兄弟组件重渲染优化:Header触发List更新且不渲染App

解决思路与方案

核心问题很明确:useRef 的值变化不会触发组件重渲染,你修改 activeUser.current 后,App 组件不会重新渲染,导致传递给 List 的 test props 始终是旧值,自然无法更新 List 内容。

下面提供两种最优解决方案,适配不同场景:


方案一:利用路由参数直接获取用户(最简洁)

你的路由已经定义了 /:userName,完全可以通过路由参数匹配用户,不需要额外维护 activeUser 状态,从根源避免不必要的重渲染:

修改步骤:

  1. App 组件:移除状态相关逻辑,简化为路由容器:
export default function App() {
  console.log("App run")
  const todosArr = useRef<task_T_Model[]>([])

  return (
    <BrowserRouter>
      <div>
        <Heder />
        <br /><br /><br /><br /><br /><br /><br />

        <Routes>
          <Route path='/' element={<Navigate replace to="/Adir" />} />
          <Route path='/:userName' element={<List />} />
        </Routes>
      </div>
    </BrowserRouter>
  )
}
  1. Header 组件:仅保留路由跳转逻辑,无需额外回调:
export default function Heder() {
  return (
    <AppBar id='heder-bar' >
      <Toolbar disableGutters>
        {
          usersArr.map((user) => (
            <h1 key={user.userid}>
              <Link to={`/${user.userName}`}>{user.userName}</Link>
            </h1>
          ))
        }
      </Toolbar>
    </AppBar>
  )
}
  1. List 组件:通过路由参数匹配对应用户:
import { useParams } from 'react-router-dom'

export default function List() {
  const { userName } = useParams<{ userName: string }>()
  const test = usersArr.find(user => user.userName === userName)

  console.log("list run")
  console.log(test)

  return (
    <div>
      {Array(9).fill(0).map((_, idx) => (
        <h1 key={idx}>{test?.userName}</h1>
      ))}
    </div>
  )
}

这种方式下,App 组件仅初始化渲染一次,Header 点击仅触发路由变化,List 组件根据路由参数自动更新内容,完全符合你的需求。


方案二:使用 React Context 隔离状态(适合复杂状态场景)

如果后续需要在多个组件共享 activeUser 状态,推荐用 Context 封装状态逻辑,避免 App 组件重渲染:

步骤:

  1. 创建 UserContext:
import { createContext, useContext, useState, useCallback } from 'react'

type UserContextType = {
  activeUser: user_T_model | undefined
  setActiveUser: (user: user_T_model) => void
}

const UserContext = createContext<UserContextType | undefined>(undefined)

export function UserProvider({ children }: { children: React.ReactNode }) {
  const [activeUser, setActiveUser] = useState<user_T_model | undefined>(
    usersArr.find(user => user.admin === true)
  )

  const updateActiveUser = useCallback((user: user_T_model) => {
    setActiveUser(user)
  }, [])

  return (
    <UserContext.Provider value={{ activeUser, setActiveUser: updateActiveUser }}>
      {children}
    </UserContext.Provider>
  )
}

export function useUser() {
  const context = useContext(UserContext)
  if (!context) throw new Error('useUser must be used within a UserProvider')
  return context
}
  1. 修改 App 组件:用 UserProvider 包裹子组件,自身不再持有状态:
import { UserProvider } from './UserContext'

export default function App() {
  console.log("App run")
  const todosArr = useRef<task_T_Model[]>([])

  return (
    <UserProvider>
      <BrowserRouter>
        <div>
          <Heder />
          <br /><br /><br /><br /><br /><br /><br />

          <Routes>
            <Route path='/' element={<Navigate replace to="/Adir" />} />
            <Route path='/:userid' element={<List />} />
          </Routes>
        </div>
      </BrowserRouter>
    </UserProvider>
  )
}
  1. Header 组件:通过自定义 Hook 获取状态更新函数:
import { useUser } from './UserContext'

export default function Heder() {
  const { setActiveUser } = useUser()

  return (
    <AppBar id='heder-bar' >
      <Toolbar disableGutters>
        {
          usersArr.map((user) => (
            <h1 key={user.userid}
              onClick={() => setActiveUser(user)}
            >
              <Link to={`/${user.userName}`}>{user.userName}</Link>
            </h1>
          ))
        }
      </Toolbar>
    </AppBar>
  )
}
  1. List 组件:通过自定义 Hook 获取活跃用户:
import { useUser } from './UserContext'

export default function List() {
  const { activeUser } = useUser()

  console.log("list run")
  console.log(activeUser)

  return (
    <div>
      {Array(9).fill(0).map((_, idx) => (
        <h1 key={idx}>{activeUser?.userName}</h1>
      ))}
    </div>
  )
}

这种方式下,App 组件仅渲染一次,只有订阅了 UserContext 的 Header 和 List 组件会在状态变化时重渲染,完美实现最小化重渲染的目标。


原方案失效原因

  • useRef 设计初衷是存储无需触发重渲染的值,修改 .current 不会通知 React 更新组件。
  • 即使你修改了 shoulsListUpdate.current,由于 App 未重渲染,传递给 List 的 test props 始终是旧的 activeUser.current,所以 List 不会更新。

内容的提问来源于stack exchange,提问作者adir

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 09:36:26