专题:Hooks 与状态

请添加图片描述

开发时刚打开页面,服务端就收到两次读取请求;发布包却只出现一次。很多人会直接移除 Strict Mode,表面安静了,但订阅泄漏、异步竞态和清理缺失也一起被藏了起来。

先理解问题

Strict Mode 会在开发环境对 Effect 增加一次设置和清理检查。工程需要满足的是:前一轮失效后不能继续改变当前界面,资源应被释放。取消请求可以节约资源,但不能保证请求尚未到达服务端,也不能代替服务端对写操作的幂等处理。

实现路径

  1. 记录 setup、cleanup 和请求编号,先确认双请求来自 Effect 检查,而非按钮绑定两次。
  2. 让每轮 Effect 拥有自己的有效标记,清理时失效;读取接口可根据环境能力额外取消。
  3. 把创建订单、支付确认这类用户动作放在事件流程,并使用稳定业务请求身份,不要绑定到“页面刚挂载”。

核心示例

import {useEffect, useState} from 'react';
export function useLabel(load: () => Promise<string>) {
  const [label, setLabel] = useState('');
  useEffect(() => {
    let active = true;
    load().then(value => {
      if (active) setLabel(value);
    }).catch(() => {
      if (active) setLabel('加载失败');
    });
    return () => { active = false; };
  }, [load]);
  return label;
}

这里的 load 是由调用方传入的稳定函数;如果每次渲染都新建它,会正常触发重新同步。active 属于单次 Effect,不会误把上一轮结果当成本轮结果。它保护的是界面提交,不会让已经发出的网络包消失。

容易忽略的边界

用一个“已经执行过”的 ref 阻止第二次 setup,可能同时阻止真正需要的重新连接。更危险的是第一次 setup 已被 cleanup 释放,第二次又被跳过,页面便留下一个看似初始化过、实际上没有资源的状态。

怎么验证

  • 人为延迟第一轮响应:最后界面应来自仍有效的一轮。
  • 返回页面后重新进入:订阅能正常建立,而不是被永久跳过。
  • 对比开发与发布日志:解释差异,但不要以次数相同作为唯一成功条件。

保留这次开发期压力检查,把清理写完整,通常比隐藏一次额外请求更有长期价值。

适用范围与参考

示例用于说明设计与排查方法,非完整应用,也不代表已经过设备实测。 组件片段需接入对应项目;文中自定义函数、示意协议和策略数值需按业务补齐。迁移到 OHOS 时应另外核对适配层支持。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐