【回顾React的一些小细节】render里不可包含的东西

在 React 的 render()(或函数组件的渲染路径)中

不应包含

  • 副作用(Side effects): 如网络请求、订阅、定时器、I/O、路由跳转等。

    • 为什么:render 应是纯函数,副作用会在每次渲染重复执行或引发循环。
    • 替代:类组件放 componentDidMount / componentDidUpdate,函数组件放 useEffect(并正确设置依赖)。
  • 调用 setState 或 导致状态变化的操作 : 直接或间接在 render 里调用 setState 会立即触发新渲染,容易导致无限循环。

    • 替代:把状态更新放到事件回调、生命周期、或 effect 中。
  • 直接修改 this.state 或可变数据(Mutation) : 如 this.state.obj.x = 1array.push()

    • 为什么:会破坏不可变性,导致难以追踪的渲染问题。
    • 替代:使用不可变拷贝:const next = {...this.state.obj, x:1}const nextArr = [...arr, item]
  • 长时间或昂贵的计算: CPU 密集型操作会阻塞渲染导致卡顿。

    • 替代:使用 useMemo / memo / PureComponent 或把计算异步化/提前计算。
  • 创建新的函数/对象引用(频繁) : 在渲染每次都新建匿名函数或对象(如 onClick={() => doX()}style={``{}})会使子组件收到不同引用,触发不必要重渲染。

    • 替代:用 class 方法、useCallbackuseMemo 或提前提取常量。
  • 直接操作 DOM 或添加事件监听 : 如 document.addEventListener、手动修改节点。

    • 替代:使用 refs + 在 componentDidMount/useEffect 中进行,并在卸载时清理。
  • 异步/await 表达式 : render 不能是异步函数,返回值必须是 React 元素或 null

    • 替代:在 effect 中做异步工作,状态准备好后渲染。
  • 非确定性副作用(例如导航、弹窗、全局状态修改): 这些在每次渲染时重复执行会造成 UX/状态错乱。

    • 替代:通过事件或 effect 控制一次性/受控触发。
  • 抛出异常的操作(未捕捉): 如果 render 抛错会破坏整棵组件树(除非有 ErrorBoundary)。

    • 替代:在渲染前验证数据,或在渲染外做可能失败的逻辑并保留安全值。

常见错误示例(错误)

jsx 复制代码
// 错误:每次 render 都会创建定时器并在回调里 setState -> 无限循环
render() {
  setTimeout(() => this.setState({ x: 1 }), 1000);
  return <div>{this.state.x}</div>;
}

正确写法(类组件)

jsx 复制代码
componentDidMount() {
  this.timer = setTimeout(() => this.setState({ x: 1 }), 1000);
}
componentWillUnmount() {
  clearTimeout(this.timer);
}
render() {
  return <div>{this.state.x}</div>;
}

正确写法(函数组件 + Hook)

jsx 复制代码
useEffect(() => {
  const id = setTimeout(() => setX(1), 1000);
  return () => clearTimeout(id);
}, []); // 空依赖:只在挂载时执行一次

(排查 render 问题时用)

  • render 中有没有 setState / setTimeout / fetch / addEventListener?若有,把它们移动到 effect 或生命周期。
  • 是否直接修改 state 或 props 的对象/数组?若是,改为不可变更新。
  • 是否每次渲染都创建了新的函数/对象作为 prop?考虑 useCallback / useMemo
  • 是否在组件卸载时清理了订阅或计时器?(componentWillUnmount / effect cleanup)
相关推荐
未来龙皇小蓝1 分钟前
RBAC前端架构-02:集成Vue Router、Vuex和Axios实现基本认证实现
前端·vue.js·架构
空白诗6 分钟前
高级进阶 React Native 鸿蒙跨平台开发:slider 滑块组件 - 进度条与评分系统
javascript·react native·react.js
空白诗7 分钟前
高级进阶React Native 鸿蒙跨平台开发:slider 滑块组件 - 音量调节器完整实现
react native·react.js·harmonyos
晓得迷路了15 分钟前
栗子前端技术周刊第 116 期 - 2025 JS 状态调查结果、Babel 7.29.0、Vue Router 5...
前端·javascript·vue.js
How_doyou_do17 分钟前
执行上下文、作用域、闭包 patch
javascript
叫我一声阿雷吧22 分钟前
深入理解JavaScript作用域和闭包,解决变量访问问题
开发语言·javascript·ecmascript
顾北1230 分钟前
AI对话应用接口开发全解析:同步接口+SSE流式+智能体+前端对接
前端·人工智能
iDao技术魔方42 分钟前
深入Vue 3响应式系统:为什么嵌套对象修改后界面不更新?
javascript·vue.js·ecmascript
历程里程碑1 小时前
普通数组-----除了自身以外数组的乘积
大数据·javascript·python·算法·elasticsearch·搜索引擎·flask
摸鱼的春哥1 小时前
春哥的Agent通关秘籍07:5分钟实现文件归类助手【实战】
前端·javascript·后端