# React性能优化策略

React应用性能优化是前端开发中的重要课题。即使React本身已经很快,但在复杂应用或低性能设备上,性能问题仍可能出现。本文将介绍一系列React性能优化策略,帮助你构建快速流畅的React应用。

# 性能瓶颈识别

在进行优化前,首先需要识别性能瓶颈所在。React提供了多种工具帮助诊断性能问题:

# React DevTools Profiler

React DevTools的Profiler是最直观的性能分析工具:

  1. 安装React DevTools (opens new window)
  2. 在DevTools中切换到Profiler选项卡
  3. 点击"Record"开始记录
  4. 执行想要分析的操作
  5. 点击"Stop"结束记录
  6. 分析渲染时间和渲染原因

# 使用Performance面板

Chrome DevTools的Performance面板提供更底层的性能分析:

  1. 打开Chrome DevTools
  2. 切换到Performance选项卡
  3. 点击"Record"
  4. 执行操作
  5. 点击"Stop"
  6. 分析JavaScript执行、布局和渲染时间

# 减少不必要的渲染

React性能优化的核心是减少不必要的渲染。

# 使用React.memo()

React.memo()是一个高阶组件,可防止组件在props未变化时重新渲染:

const TodoItem = React.memo(function TodoItem({ text, completed, onToggle }) {
  console.log(`Rendering: ${text}`)
  return (
    <li
      onClick={onToggle}
      style={{ textDecoration: completed ? 'line-through' : 'none' }}
    >
      {text}
    </li>
  )
})
1
2
3
4
5
6
7
8
9
10
11

注意:React.memo()只进行props的浅比较。对于对象类型的props,需要确保引用不变或提供自定义比较函数:

const TodoItem = React.memo(
  function TodoItem({ todo, onToggle }) {
    return (
      <li
        onClick={() => onToggle(todo.id)}
        style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}
      >
        {todo.text}
      </li>
    )
  },
  (prevProps, nextProps) => {
    // 只有当id、text或completed改变时才重新渲染
    return prevProps.todo.id === nextProps.todo.id &&
           prevProps.todo.text === nextProps.todo.text &&
           prevProps.todo.completed === nextProps.todo.completed
  }
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 使用useMemouseCallback

useMemo缓存计算结果,useCallback缓存函数引用,防止不必要的重新计算或函数创建:

function TodoList({ todos, filter }) {
  // 缓存过滤计算结果
  const filteredTodos = useMemo(() => {
    console.log('Filtering todos')
    return todos.filter(todo => {
      if (filter === 'all') return true
      if (filter === 'completed') return todo.completed
      if (filter === 'active') return !todo.completed
      return true
    })
  }, [todos, filter]) // 只有当todos或filter变化时才重新计算
  
  // 缓存回调函数
  const handleToggle = useCallback((id) => {
    console.log('Creating toggle handler')
    // 切换完成状态的逻辑
  }, []) // 空依赖数组意味着此函数永不重新创建
  
  return (
    <ul>
      {filteredTodos.map(todo => (
        <TodoItem
          key={todo.id}
          todo={todo}
          onToggle={handleToggle}
        />
      ))}
    </ul>
  )
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# 使用React.PureComponent(类组件)

对于类组件,可以继承PureComponent而非Component,实现浅比较优化:

import React, { PureComponent } from 'react'

class TodoItem extends PureComponent {
  render() {
    const { text, completed, onToggle } = this.props
    return (
      <li
        onClick={onToggle}
        style={{ textDecoration: completed ? 'line-through' : 'none' }}
      >
        {text}
      </li>
    )
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 列表优化

列表渲染是React应用中的常见性能瓶颈。

# 使用唯一且稳定的key

始终为列表项提供唯一且稳定的key:

// 不好的例子 - 使用索引作为key
{items.map((item, index) => (
  <ListItem key={index} item={item} />
))}

// 好的例子 - 使用稳定唯一ID
{items.map(item => (
  <ListItem key={item.id} item={item} />
))}
1
2
3
4
5
6
7
8
9

索引作为key的问题在于,当列表项重新排序时,React会错误地认为内容已改变,导致不必要的重新渲染。

# 虚拟化长列表

对于长列表,使用虚拟化技术只渲染可见区域的项:

import { FixedSizeList } from 'react-window'

function VirtualizedList({ items }) {
  const Row = ({ index, style }) => (
    <div style={style}>
      <TodoItem todo={items[index]} />
    </div>
  )
  
  return (
    <FixedSizeList
      height={500}
      width="100%"
      itemCount={items.length}
      itemSize={35}
    >
      {Row}
    </FixedSizeList>
  )
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

常用的虚拟化库有:

# 状态管理优化

# 状态拆分与局部化

将应用状态拆分为多个小型、独立的部分,使更新更加局部化:

// 不好的例子 - 单一大状态
function App() {
  const [state, setState] = useState({
    todos: [],
    filter: 'all',
    theme: 'light',
    user: null
  })
  
  // 更新会导致整个应用重新渲染
  const updateTheme = theme => {
    setState(prev => ({ ...prev, theme }))
  }
  
  // ...
}

// 好的例子 - 状态拆分
function App() {
  const [todos, setTodos] = useState([])
  const [filter, setFilter] = useState('all')
  const [theme, setTheme] = useState('light')
  const [user, setUser] = useState(null)
  
  // 更新只影响相关组件
  const updateTheme = newTheme => {
    setTheme(newTheme)
  }
  
  // ...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

# 状态提升限制

只将状态提升到必要的最低共同祖先,避免过度提升:

function TodoApp() {
  // 全局过滤器状态 - 需要被多个组件共享
  const [filter, setFilter] = useState('all')
  
  return (
    <div>
      <FilterControls filter={filter} setFilter={setFilter} />
      <TodoList filter={filter} />
    </div>
  )
}

function TodoList({ filter }) {
  // 局部todos状态 - 只在TodoList及其子组件中使用
  const [todos, setTodos] = useState([])
  
  return (
    <div>
      <AddTodo onAdd={todo => setTodos(prev => [...prev, todo])} />
      <ul>
        {todos
          .filter(todo => {
            if (filter === 'all') return true
            if (filter === 'completed') return todo.completed
            return !todo.completed
          })
          .map(todo => (
            <TodoItem
              key={todo.id}
              todo={todo}
              onChange={updatedTodo => {
                setTodos(todos.map(t => 
                  t.id === updatedTodo.id ? updatedTodo : t
                ))
              }}
            />
          ))}
      </ul>
    </div>
  )
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

# 上下文优化

Context API可能导致大范围重渲染。优化策略包括:

  1. 拆分Context - 按领域划分多个小Context,而非一个大Context
  2. 使用useMemo缓存Context值 - 防止Context Provider重新渲染时触发所有消费组件更新
// 拆分Context
const ThemeContext = React.createContext()
const UserContext = React.createContext()
const TodosContext = React.createContext()

function App() {
  const [theme, setTheme] = useState('light')
  const [user, setUser] = useState(null)
  const [todos, setTodos] = useState([])
  
  // 使用useMemo缓存Context值
  const themeContextValue = useMemo(() => ({
    theme,
    setTheme
  }), [theme])
  
  const userContextValue = useMemo(() => ({
    user,
    setUser
  }), [user])
  
  const todosContextValue = useMemo(() => ({
    todos,
    setTodos
  }), [todos])
  
  return (
    <ThemeContext.Provider value={themeContextValue}>
      <UserContext.Provider value={userContextValue}>
        <TodosContext.Provider value={todosContextValue}>
          <Main />
        </TodosContext.Provider>
      </UserContext.Provider>
    </ThemeContext.Provider>
  )
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

# 代码分割与懒加载

# 使用dynamic import和React.lazy

使用代码分割减小主包体积,按需加载组件:

import React, { Suspense, lazy } from 'react'
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'

// 懒加载路由组件
const Home = lazy(() => import('./routes/Home'))
const Dashboard = lazy(() => import('./routes/Dashboard'))
const Settings = lazy(() => import('./routes/Settings'))

function App() {
  return (
    <Router>
      <Suspense fallback={<div>Loading...</div>}>
        <Switch>
          <Route exact path="/" component={Home} />
          <Route path="/dashboard" component={Dashboard} />
          <Route path="/settings" component={Settings} />
        </Switch>
      </Suspense>
    </Router>
  )
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 组件懒加载

对于条件显示的大型组件,也可以使用懒加载:

const LargeDataChart = lazy(() => import('./components/LargeDataChart'))

function Dashboard() {
  const [showChart, setShowChart] = useState(false)
  
  return (
    <div>
      <button onClick={() => setShowChart(true)}>
        Show Chart
      </button>
      
      {showChart && (
        <Suspense fallback={<div>Loading chart...</div>}>
          <LargeDataChart />
        </Suspense>
      )}
    </div>
  )
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 避免昂贵的操作阻塞主线程

# 使用Web Workers

对于CPU密集型操作,可以使用Web Workers将其移至后台线程:

// worker.js
self.addEventListener('message', event => {
  const { data, operationType } = event.data
  
  if (operationType === 'processLargeArray') {
    // 执行复杂计算
    const result = data.map(item => /* 复杂处理 */)
      .filter(item => /* 更多处理 */)
      .reduce((acc, item) => /* 最终计算 */, initialValue)
      
    self.postMessage({ result, operationType })
  }
})

// React组件
function DataProcessor() {
  const [result, setResult] = useState(null)
  const [processing, setProcessing] = useState(false)
  const workerRef = useRef(null)
  
  useEffect(() => {
    // 创建Worker
    workerRef.current = new Worker('./worker.js')
    
    // 设置消息处理器
    workerRef.current.addEventListener('message', event => {
      if (event.data.operationType === 'processLargeArray') {
        setResult(event.data.result)
        setProcessing(false)
      }
    })
    
    return () => {
      workerRef.current.terminate()
    }
  }, [])
  
  const processData = () => {
    setProcessing(true)
    const largeArray = generateLargeArray() // 假设此函数生成大量数据
    workerRef.current.postMessage({
      data: largeArray,
      operationType: 'processLargeArray'
    })
  }
  
  return (
    <div>
      <button onClick={processData} disabled={processing}>
        {processing ? '处理中...' : '处理数据'}
      </button>
      {result && <div>结果: {result}</div>}
    </div>
  )
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

# 时间切片

对于不能使用Worker的场景,可以使用时间切片技术:

function processChunk(array, chunkIndex, chunkSize, callback, finishCallback) {
  const start = chunkIndex * chunkSize
  const end = Math.min(start + chunkSize, array.length)
  
  // 处理当前块
  let result = 0
  for (let i = start; i < end; i++) {
    result += heavyComputation(array[i])
  }
  
  // 调用进度回调
  callback(result, Math.floor((end / array.length) * 100))
  
  // 检查是否完成
  if (end < array.length) {
    // 使用setTimeout将控制权交还给浏览器,避免长时间阻塞
    setTimeout(() => {
      processChunk(array, chunkIndex + 1, chunkSize, callback, finishCallback)
    }, 0)
  } else {
    finishCallback()
  }
}

function ChunkedProcessor() {
  const [progress, setProgress] = useState(0)
  const [result, setResult] = useState(0)
  const [processing, setProcessing] = useState(false)
  
  const startProcessing = () => {
    setProcessing(true)
    setProgress(0)
    
    const largeArray = generateLargeArray(10000) // 生成大量数据
    
    processChunk(
      largeArray,
      0, // 起始块索引
      100, // 每块大小
      (chunkResult, progressPercent) => {
        setResult(prev => prev + chunkResult)
        setProgress(progressPercent)
      },
      () => {
        setProcessing(false)
      }
    )
  }
  
  return (
    <div>
      <button onClick={startProcessing} disabled={processing}>
        开始处理
      </button>
      {processing && <progress value={progress} max="100" />}
      <div>结果: {result}</div>
    </div>
  )
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

# DOM操作优化

# 批量处理DOM更新

React已经批处理大部分状态更新,但在某些情况下可能失效(如异步回调中的多次更新)。React 18的自动批处理解决了这个问题,如果使用旧版本,可以使用以下策略:

// React 17或更早版本
import { unstable_batchedUpdates } from 'react-dom'

function UserProfile() {
  const [name, setName] = useState('')
  const [email, setEmail] = useState('')
  const [bio, setBio] = useState('')
  
  const fetchUserData = () => {
    fetch('/api/user')
      .then(res => res.json())
      .then(user => {
        // 包装在batchedUpdates中,确保这些更新被批处理
        unstable_batchedUpdates(() => {
          setName(user.name)
          setEmail(user.email)
          setBio(user.bio)
        })
      })
  }
  
  // ...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# React性能优化策略

React应用性能优化是前端开发中的重要课题。即使React本身已经很快,但在复杂应用或低性能设备上,性能问题仍可能出现。本文将介绍一系列React性能优化策略,帮助你构建快速流畅的React应用。

...(about 249 lines omitted)...

# 优化大型表单

对于大型表单,使用单一状态和受控组件可能导致性能问题:

// 性能更好的表单处理
function LargeForm() {
  const formRef = useRef({})
  const [submitData, setSubmitData] = useState(null)
  
  const handleChange = (e) => {
    // 使用非受控方式更新表单数据,不触发重渲染
    formRef.current[e.target.name] = e.target.value
  }
  
  const handleSubmit = (e) => {
    e.preventDefault()
    // 只在表单提交时更新状态,触发一次渲染
    setSubmitData({...formRef.current})
  }
  
  return (
    <form onSubmit={handleSubmit}>
      <input name="field1" onChange={handleChange} defaultValue="" />
      <input name="field2" onChange={handleChange} defaultValue="" />
      {/* 假设有几十个表单字段 */}
      <button type="submit">提交</button>
      
      {submitData && (
        <div>
          <h3>提交的数据:</h3>
          <pre>{JSON.stringify(submitData, null, 2)}</pre>
        </div>
      )}
    </form>
  )
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

对于需要即时验证的表单,可以结合使用:

function ValidatedLargeForm() {
  // 只存储需要即时反馈的字段
  const [email, setEmail] = useState('')
  const [emailError, setEmailError] = useState('')
  
  // 其他字段使用ref存储
  const formRef = useRef({})
  
  const validateEmail = (value) => {
    const isValid = /\S+@\S+\.\S+/.test(value)
    setEmailError(isValid ? '' : '请输入有效的邮箱地址')
    return isValid
  }
  
  const handleEmailChange = (e) => {
    const value = e.target.value
    setEmail(value)
    validateEmail(value)
  }
  
  const handleOtherFieldChange = (e) => {
    formRef.current[e.target.name] = e.target.value
  }
  
  const handleSubmit = (e) => {
    e.preventDefault()
    if (validateEmail(email)) {
      const formData = {
        ...formRef.current,
        email
      }
      // 处理表单提交
      console.log('提交数据', formData)
    }
  }
  
  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label>邮箱 (即时验证):</label>
        <input 
          type="email" 
          value={email} 
          onChange={handleEmailChange} 
        />
        {emailError && <span style={{color: 'red'}}>{emailError}</span>}
      </div>
      
      <div>
        <label>名字:</label>
        <input name="name" onChange={handleOtherFieldChange} defaultValue="" />
      </div>
      
      {/* 其他非即时验证字段 */}
      
      <button type="submit">提交</button>
    </form>
  )
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

# 代码分割与懒加载

对于大型应用,将代码分割成较小的块并按需加载非常重要。

# 使用React.lazy和Suspense

import React, { Suspense, lazy } from 'react'
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'

// 懒加载路由组件
const Home = lazy(() => import('./pages/Home'))
const Dashboard = lazy(() => import('./pages/Dashboard'))
const Settings = lazy(() => import('./pages/Settings'))

function App() {
  return (
    <Router>
      <Suspense fallback={<div>加载中...</div>}>
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/dashboard" element={<Dashboard />} />
          <Route path="/settings" element={<Settings />} />
        </Routes>
      </Suspense>
    </Router>
  )
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 基于交互的代码分割

某些组件可以基于用户交互懒加载:

function ProductPage() {
  const [showDetails, setShowDetails] = useState(false)
  const ProductDetails = lazy(() => import('./ProductDetails'))
  
  return (
    <div>
      <h1>产品基本信息</h1>
      <button onClick={() => setShowDetails(true)}>
        查看详情
      </button>
      
      {showDetails && (
        <Suspense fallback={<div>加载详情...</div>}>
          <ProductDetails />
        </Suspense>
      )}
    </div>
  )
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 渲染优化

# 使用Fragments避免额外的DOM节点

function UserInfo({ user }) {
  return (
    <>
      <h2>{user.name}</h2>
      <p>{user.bio}</p>
    </>
  )
}
1
2
3
4
5
6
7
8

# 合理使用Context

Context是一个强大的功能,但如果使用不当,会导致性能问题:

// 分割Context以避免不必要的重渲染
const ThemeContext = React.createContext()
const UserContext = React.createContext()

function App() {
  const [theme, setTheme] = useState('light')
  const [user, setUser] = useState(null)
  
  // 分离提供者,避免一个状态变化导致所有消费者重渲染
  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      <UserContext.Provider value={{ user, setUser }}>
        <MainApp />
      </UserContext.Provider>
    </ThemeContext.Provider>
  )
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 服务端渲染(SSR)和静态生成(SSG)

对于内容密集型应用,考虑使用Next.js等框架实现SSR或SSG:

// pages/index.js (Next.js)
export async function getStaticProps() {
  const res = await fetch('https://api.example.com/posts')
  const posts = await res.json()
  
  return {
    props: {
      posts,
    },
    // 每小时重新生成
    revalidate: 3600,
  }
}

function Blog({ posts }) {
  return (
    <div>
      <h1>博客文章</h1>
      <ul>
        {posts.map(post => (
          <li key={post.id}>{post.title}</li>
        ))}
      </ul>
    </div>
  )
}

export default Blog
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

# 部署优化

# 启用生产模式

确保生产构建使用了生产模式:

# 使用环境变量
NODE_ENV=production npm run build
1
2

# 使用代码压缩和Tree Shaking

在webpack配置中启用:

// webpack.config.js
module.exports = {
  mode: 'production', // 启用所有优化
  optimization: {
    usedExports: true, // 标记未使用的导出
    minimize: true, // 压缩代码
  }
}
1
2
3
4
5
6
7
8

# 实际案例分析

# 案例:优化大型数据表格

在字节跳动的项目中,我们需要处理包含数千行的数据表格。以下是我们采用的优化策略:

function OptimizedDataTable({ data, columns }) {
  // 1. 虚拟化列表
  const VirtualizedList = useCallback(({ items, height, itemHeight }) => {
    const [startIndex, setStartIndex] = useState(0)
    const containerRef = useRef(null)
    
    // 计算可见行数
    const visibleItemsCount = Math.ceil(height / itemHeight) + 2 // 额外渲染2行作为缓冲
    
    // 监听滚动更新起始索引
    const handleScroll = useCallback(() => {
      const scrollTop = containerRef.current.scrollTop
      const newStartIndex = Math.floor(scrollTop / itemHeight)
      setStartIndex(newStartIndex)
    }, [itemHeight])
    
    useEffect(() => {
      const container = containerRef.current
      container.addEventListener('scroll', handleScroll)
      return () => container.removeEventListener('scroll', handleScroll)
    }, [handleScroll])
    
    // 计算可见项
    const visibleItems = items.slice(startIndex, startIndex + visibleItemsCount)
    
    return (
      <div
        ref={containerRef}
        style={{ height, overflow: 'auto' }}
      >
        <div style={{ height: items.length * itemHeight, position: 'relative' }}>
          <div style={{ position: 'absolute', top: startIndex * itemHeight }}>
            {visibleItems.map((item, index) => (
              <TableRow 
                key={item.id} 
                data={item} 
                columns={columns}
                style={{ height: itemHeight }}
              />
            ))}
          </div>
        </div>
      </div>
    )
  }, [columns])
  
  // 2. 使用Web Worker排序和过滤
  const [filteredData, setFilteredData] = useState(data)
  const [filter, setFilter] = useState('')
  const [sortConfig, setSortConfig] = useState(null)
  const workerRef = useRef(null)
  
  useEffect(() => {
    workerRef.current = new Worker('/dataWorker.js')
    
    workerRef.current.onmessage = (e) => {
      setFilteredData(e.data)
    }
    
    return () => workerRef.current.terminate()
  }, [])
  
  useEffect(() => {
    workerRef.current.postMessage({
      data,
      filter,
      sortConfig
    })
  }, [data, filter, sortConfig])
  
  // 3. 记忆化表头组件
  const TableHeader = useMemo(() => {
    return (
      <div className="table-header">
        {columns.map(column => (
          <div 
            key={column.key} 
            className="header-cell"
            onClick={() => {
              // 点击表头排序
              setSortConfig({
                key: column.key,
                direction: 
                  sortConfig?.key === column.key && sortConfig?.direction === 'asc' 
                    ? 'desc' 
                    : 'asc'
              })
            }}
          >
            {column.title}
            {sortConfig?.key === column.key && (
              <span>{sortConfig.direction === 'asc' ? '↑' : '↓'}</span>
            )}
          </div>
        ))}
      </div>
    )
  }, [columns, sortConfig])
  
  return (
    <div className="data-table-container">
      <div className="table-controls">
        <input 
          type="text"
          placeholder="过滤数据..."
          value={filter}
          onChange={(e) => setFilter(e.target.value)}
        />
      </div>
      
      {TableHeader}
      
      <VirtualizedList 
        items={filteredData}
        height={500} // 表格可视区域高度
        itemHeight={40} // 每行高度
      />
      
      <div className="table-footer">{filteredData.length} 条数据
      </div>
    </div>
  )
}

// 记忆化表格行组件
const TableRow = React.memo(function TableRow({ data, columns, style }) {
  return (
    <div className="table-row" style={style}>
      {columns.map(column => (
        <div key={column.key} className="table-cell">
          {column.render ? column.render(data) : data[column.key]}
        </div>
      ))}
    </div>
  )
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137

# 总结

React性能优化是一个持续的过程,需要先识别问题,然后有针对性地应用适当的优化技术。本文介绍的策略涵盖了:

  1. 渲染优化 - 减少组件重渲染
  2. 列表优化 - 优化大量数据渲染
  3. 计算优化 - 使用记忆化和Web Workers
  4. 代码分割 - 减少初始加载时间
  5. 服务端渲染 - 改善首屏加载体验

在我的实践中,最有效的性能优化往往来自于架构层面的决策,而不仅仅是代码层面的小优化。

# 学习资源

Last Updated: 2025-03-11T08:38:33.000Z