SuperAPI AI 工具集

solidjs-patterns

前端与建站

查看项目

更新于 10-15 02:52

技能介绍

用途

solidjs-patterns 是 OpenWork 项目中的一项技能,用于统一 SolidJS 的响应式与 UI 状态写法。OpenWork 的 UI 使用 SolidJS,它通过 signals 更新,而不是 React 风格的重渲染。该技能指出,大多数“UI 卡住”的 bug 实际上是状态耦合 bug(例如一个全局 busy() 禁用了不相关的操作),而不是重渲染问题。

核心规则

  • 优先使用细粒度 signals,而不是共享的全局标志。
  • 保持异步操作作用域化(每个操作拥有自己的 pending 状态)。
  • 通过 createMemo() 派生 UI 状态,而不是重复定义布尔值。
  • 避免修改存放在 signals 中的数组/对象;始终创建新值。

作用域化异步操作(推荐)

当一个操作可能与其他操作重叠时(权限、安装、后台刷新),不要复用全局 busy()。为每个操作使用专用 signal:

const [replying, setReplying] = createSignal(false);

async function respond() {
  if (replying()) return;
  setReplying(true);
  try {
    await doTheThing();
  } finally {
    setReplying(false);
  }
}

原因:单个 busy() 布尔值会造成死锁:

  • 长时间运行的任务设置 busy(true)
  • 出现权限提示,其按钮被 busy() 禁用
  • 任务在权限被应答前无法继续
  • 用户因为按钮被禁用而无法应答

修复方式:权限 UI 只能由权限专用的 pending 状态禁用。

异步处理器中的 signal 快照

如果在异步函数内部读取 signals,并且需要稳定的值,应尽早快照:

const request = activePermission();
if (!request) return;
const requestID = request.id;

await respondPermission(requestID, "always");

派生 UI 状态

对于计算出的禁用状态,优先使用 createMemo():

const canSend = createMemo(() => prompt().trim().length > 0 && !busy());

列表

对派生更新使用 setter 回调:

setItems((current) => current.filter((x) => x.id !== id));

不要就地修改 current。

实用检查清单(SolidJS UI 改动)

  • 是否有任何按钮依赖一个在长时间运行工作期间可能为 true 的全局标志?
  • 两个异步操作是否可能重叠并争抢同一个布尔值?
  • 是否有任何 UI 状态被重复定义(本可以派生)?
  • 事件处理器是否在 await 之后读取 signals,而值可能已经改变?
  • 如果重构了 props/types,是否更新了所有中间组件签名和调用点?

参考

  • SolidJS: https://www.solidjs.com/docs/latest
  • SolidJS signals: https://www.solidjs.com/docs/latest/api#createsignal
  • SolidJS memos: https://www.solidjs.com/docs/latest/api#creatememo