Files
skillhub-088-vercel-react-b…/rules/rerender-no-inline-components.md
2026-07-13 21:36:17 +08:00

2.1 KiB

title, impact, impactDescription, tags
title impact impactDescription tags
不要在组件内部定义组件 HIGH 阻止每次渲染时重新挂载 rerender, components, remount, performance

不要在组件内部定义组件

影响:高(阻止每次渲染时重新挂载)

在另一个组件内部定义组件,会在每次渲染时创建一个新的组件类型。React 每次看到的是不同的组件,因此会完全重新挂载它,销毁所有状态和 DOM。

开发者这样做的一个常见原因是为了在不传递 props 的情况下访问父组件的变量。请始终改用传递 props 的方式。

错误写法(每次渲染都重新挂载):

function UserProfile({ user, theme }) {
  // 为了访问 `theme` 而在内部定义 - 错误
  const Avatar = () => (
    <img
      src={user.avatarUrl}
      className={theme === 'dark' ? 'avatar-dark' : 'avatar-light'}
    />
  )

  // 为了访问 `user` 而在内部定义 - 错误
  const Stats = () => (
    <div>
      <span>{user.followers} followers</span>
      <span>{user.posts} posts</span>
    </div>
  )

  return (
    <div>
      <Avatar />
      <Stats />
    </div>
  )
}

每次 UserProfile 渲染时,AvatarStats 都是新的组件类型。React 会卸载旧实例并挂载新实例,丢失所有内部状态,重新运行 effect,并重建 DOM 节点。

正确写法(改为传递 props):

function Avatar({ src, theme }: { src: string; theme: string }) {
  return (
    <img
      src={src}
      className={theme === 'dark' ? 'avatar-dark' : 'avatar-light'}
    />
  )
}

function Stats({ followers, posts }: { followers: number; posts: number }) {
  return (
    <div>
      <span>{followers} followers</span>
      <span>{posts} posts</span>
    </div>
  )
}

function UserProfile({ user, theme }) {
  return (
    <div>
      <Avatar src={user.avatarUrl} theme={theme} />
      <Stats followers={user.followers} posts={user.posts} />
    </div>
  )
}

此错误的症状:

  • 输入框在每次按键后失去焦点
  • 动画意外重新开始
  • useEffect 的清理/设置逻辑在每次父组件渲染时执行
  • 组件内的滚动位置重置