news 2026/5/26 6:28:14

React 组件 业务逻辑编码 最佳实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
React 组件 业务逻辑编码 最佳实践

当我们强调“组件 Render 阶段必须纯净”时,很多刚接触 Hooks 的开发者会产生困惑:如果不写在组件函数体里,我的业务逻辑到底该往哪放?

核心的秘密在于:我们需要把“业务逻辑”分类。并不是所有业务逻辑都是“副作用”。在 React 中,业务逻辑根据其性质,有四个完美的去处。


业务逻辑的四大分类与去处

1. 纯计算逻辑(计算衍生状态)→\rightarrow直接写在函数体内

如果你的业务逻辑是根据现有的 Props 或 State 计算出一个新数据(例如:对列表进行搜索过滤、格式化时间、计算总价),这属于纯计算,没有任何副作用。

  • 怎么写:直接写在组件函数体内。每次渲染重新计算是完全可接受的(如果计算量极大,才用useMemo包裹)。
  • ❌ 错误做法:用useEffect监听状态变化,然后去setFilteredList(这会导致二次渲染)。
functionProductList({products,filterKeyword}){// ✅ 正确:纯计算逻辑,直接写在函数体内constfilteredProducts=products.filter(p=>p.name.includes(filterKeyword))consttotalPrice=filteredProducts.reduce((sum,p)=>sum+p.price,0)return<div>总价:{totalPrice}</div>}

2. 用户触发的业务(数据提交/修改)→\rightarrow写在事件处理函数或 React 19 Actions 中

如果你的业务逻辑是因为用户点了某个按钮、提交了表单才触发的(例如:删除商品、点赞、提交注册),这属于主动意图

  • 怎么写:写在onClickonSubmit等事件回调函数内部,或者利用 React 19 的Actions(结合useTransition来处理异步提交。
  • 特点:这些函数只在事件发生时调用,绝对不会在 Render 阶段自动执行,因此你可以安全地在里面写任何副作用(如fetch、修改全局状态)。
functionDeleteButton({id}){const[isPending,startTransition]=useTransition()consthandleDelete=()=>{// ✅ 正确:在事件触发的 Action 中编写异步业务逻辑startTransition(async()=>{awaitfetch(`/api/delete/${id}`,{method:'POST'})// 更新状态...})}return(<button onClick={handleDelete}disabled={isPending}>删除</button>)}

3. 被动同步逻辑(依赖外部系统)→\rightarrow写在useEffect或 React 19use()

如果你的业务逻辑是组件一旦加载出来,或者某个依赖变了,就必须自动去干的一件事(例如:进入页面自动埋点、根据用户 ID 自动获取详情、订阅 WebSocket)。

  • 怎么写:写在useEffect中,或者在 React 19 中使用use(Promise)进行声明式的数据流读取。
useEffect(()=>{// ✅ 正确:属于被动同步的副作用,放在 useEffect 中consttracker=newAnalyticsTracker()tracker.sendPageView()return()=>tracker.disconnect()// 别忘了清理},[])

4. 复杂的跨组件业务→\rightarrow抽离到自定义 Hook(Custom Hook)中

当一个组件里塞满了大量的状态、事件处理、和计算,代码变得臃肿时,最优雅的解决方案是把业务逻辑彻底抽离出 UI 组件

  • 怎么写:创建一个以use开头的自定义 Hook,把useStateuseEffect、各种计算函数都打包塞进去,组件只负责看图说话(渲染 UI)。
// 📦 独立的业务逻辑层 (useCart.js)functionuseCart(){const[items,setItems]=useState([])consttotalPrice=items.reduce((sum,i)=>sum+i.price,0)constaddItem=item=>setItems([...items,item])return{items,totalPrice,addItem}}// 🎨 纯粹的 UI 渲染层 (CartComponent.js)functionCartComponent(){// 组件体内只有一行干净的解构,没有任何杂乱的业务逻辑const{items,totalPrice,addItem}=useCart()return(<button onClick={()=>addItem({price:10})}>加购({totalPrice})</button>)}

总结速查表

业务逻辑类型举例应该写在哪里?是否允许副作用?
衍生数据计算过滤列表、计算总和、格式化文本组件函数体内❌ 绝对不行(必须是纯函数)
用户交互响应点击保存、删除、切换开关事件处理函数 / Actions✅ 可以
外部系统同步页面加载取数、监听窗口大小**useEffect/use()**✅ 可以
复杂/复用业务完整的购物车逻辑、分页器逻辑自定义 Hooks视内部的具体 Hooks 而定

把 UI(怎么画)和业务(怎么算/怎么变)通过上述规则清晰地解耦,就是写出高质量、可维护 React 19 代码的关键。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/26 6:28:14

基于Amazon Bedrock的提示工程实战:构建AI驱动的灾难恢复工具包

1. 项目概述&#xff1a;基于Amazon Bedrock构建的AI驱动灾难恢复工具包在AWS云上构建具备韧性的应用&#xff0c;灾难恢复&#xff08;DR&#xff09;规划是每个架构师和工程师都无法绕开的课题。然而&#xff0c;从零开始撰写一份详尽的恢复手册、评估RTO/RPO目标、审计现有架…

作者头像 李华
网站建设 2026/5/26 6:26:58

饲料颗粒机生产商哪家靠谱

行业痛点&#xff1a;技术挑战与数据背后的真相在饲料颗粒机行业&#xff0c;用户最常抱怨的问题集中于设备的核心性能与可靠性。根据行业调研数据&#xff0c;约65% 的饲料生产企业在使用颗粒机的前两年内&#xff0c;会遇到磨盘与压辊磨损严重、频繁更换的问题&#xff0c;导…

作者头像 李华
网站建设 2026/5/26 6:16:22

联发科设备深度解锁:从零开始掌握mtkclient-gui的实用指南

联发科设备深度解锁&#xff1a;从零开始掌握mtkclient-gui的实用指南 【免费下载链接】mtkclient-gui GUI tool for unlocking bootloader and bypassing authorization on Mediatek devices (Not maintained anymore) 项目地址: https://gitcode.com/gh_mirrors/mt/mtkclie…

作者头像 李华
网站建设 2026/5/26 6:12:07

linux环境下替换jar包中class文件或jar包方式

linux替换jar包中class文件或jar包替换class文件1234jar tvf app.jar | grep Test.class # 查询出文件路径jar -xvf app.jar BOOT-INF/classes/com/test/Test.class #解压缩指定文件cp Test.class BOOT-INF/classes/com/test/Test.class #替换文件jar -uvf app.jar BOOT-INF/…

作者头像 李华