React

38 阅读2分钟

1. 状态管理与数据流控制

随着应用规模扩大,组件间状态共享变得复杂。虽然React提供了Context API和useReducer等内置解决方案,但对于大型应用来说仍然不够。

解决方案

  • Redux:提供可预测的状态管理,但样板代码较多
  • MobX:基于响应式编程,更适合中小型应用
  • Recoil:Facebook推出的实验性状态管理库,更符合React思维
  • Zustand:轻量级解决方案,API简洁

现代趋势是结合Context API和useReducer创建局部状态管理,避免全局状态污染。

2. 性能优化

React的虚拟DOM虽然高效,但不恰当的组件设计仍会导致性能问题。

常见问题及优化方案

  • 不必要的重新渲染:使用React.memo进行组件记忆,谨慎使用useCallback和useMemo
  • 大型列表渲染:采用虚拟滚动技术(react-window或react-virtualized)
  • 复杂计算:使用useMemo缓存计算结果
  • 状态更新批处理:React 18的自动批处理减少了不必要的渲染

jsx

const ExpensiveComponent = React.memo(({ data }) => {
  const processedData = useMemo(() => processData(data), [data]);
  // ...
});

3. Hooks的合理使用

Hooks极大提高了代码复用性,但也带来了新的挑战。

常见陷阱

  • 依赖数组问题:忘记添加依赖或错误添加依赖导致无限循环
  • 条件执行Hooks:违反Hooks调用规则
  • 闭包陷阱:过时的闭包值
  • 内存泄漏:未正确清理副作用

最佳实践

jsx

useEffect(() => {
  const controller = new AbortController();
  
  const fetchData = async () => {
    try {
      const result = await fetch(url, { signal: controller.signal });
      // 处理结果
    } catch (error) {
      if (error.name !== 'AbortError') {
        // 处理错误
      }
    }
  };

  fetchData();
  
  return () => controller.abort();
}, [url]); // 正确声明依赖

4. 服务器组件与并发模式(React 18+)

React 18引入的并发特性带来了新的编程模型,也增加了复杂度。

难点解析

  • 服务器组件:需要理解组件在服务端和客户端的执行差异
  • 过渡更新:使用startTransition标记非紧急更新
  • Suspense集成:优雅处理异步操作和加载状态
  • 流式SSR:理解HTML流的处理方式

jsx

function App() {
  const [resource, setResource] = useState(initialResource);

  const handleClick = () => {
    startTransition(() => {
      setResource(fetchNewResource());
    });
  };

  return (
    <Suspense fallback={<Spinner />}>
      <Profile resource={resource} />
    </Suspense>
  );
}

5. 测试策略

React应用的测试复杂度高,需要综合考虑组件渲染、状态变化和副作用。

全面测试方案

  • 单元测试:使用Jest测试纯函数和自定义Hooks
  • 组件测试:使用React Testing Library测试组件行为
  • 集成测试:验证多个组件的交互
  • E2E测试:使用Cypress或Playwright测试完整用户流程

jsx

test('should increment counter', async () => {
  const { getByText, findByText } = render(<Counter />);
  fireEvent.click(getByText('Increment'));
  expect(await findByText('Count: 1')).toBeInTheDocument();
});