
字节笔记本
2026年10月7日 · 约 2 分钟读完
勾选不会让卡片变淡
组件文件开头是 use client。待办卡片放在一个没有动作的 form 里。useFormStatus 的 pending 为真时,卡片透明度变成一半,勾选和删除按钮被禁用。
只有删除走表单动作
删除按钮的 formAction 里先做乐观更新,动作名是 delete,再调用 deleteTodo,参数是这条的编号。乐观更新没有包在失败回滚里。勾选的 onCheckedChange 若遇到 indeterminate 就返回。否则先改本地勾选,再把整条待办拷贝一份、换上新的完成状态,调用 updateTodo。这条调用不是 formAction。pending 只跟着当前表单提交走,所以勾选期间它仍是假,卡片不会变淡,勾选也不会被禁用。
服务端三个函数都先取当前用户,没有用户就抛出未登录。新增从字段 todo 取文本,空文本抛出 Text is required,插入 task 和 user_id。删除和更新都用 user_id 加上编号做 match。更新把整份待办对象交进去。出错时的句子分别是新增失败、删除失败、更新失败。三处最后都 revalidatePath,路径是 /todos。
两段指令被粘在一起
粘贴的前半是 use client,后半紧跟着 use server 和这三个函数。同一文件开头已经是客户端指令时,不能再在文件顶部放服务器指令。服务器函数要单独放,客户端用导入来调用。对话把三个函数说成在动作文件里。以粘贴的顺序看,它们当时连在同一段里。

更新交的是整份对象。表里没有的字段会让更新失败,失败句子仍是那句泛泛的更新失败,看不出是字段问题。
删除的乐观更新发生在请求之前。请求抛错时,对话没有把条目加回去。界面会先空一格,刷新之后才和服务器对齐。

路径写死为 /todos。页面不在这条路径上,重新验证不会刷新你正在看的列表。
勾选的本地状态用的是初始的 is_complete。服务器更新成功但没有把新值写回这条属性时,下一次从父组件传入才会对齐。等待期间卡片不变淡,不能用来判断更新是否发出。
表单没有自己的 action。提交依赖按钮上的 formAction。勾选控件不在这条提交里。



