You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Svelte派生存储返回错误值问题排查

Svelte待办表单验证问题排查与解决

问题场景

实现了基于Svelte store的待办事项表单,将表单逻辑抽象到store中,使用派生store error 处理提交验证。但点击「Add Todo」按钮时,首次会添加空待办项,之后才显示对应的错误提示。

代码示例

App.svelte

<script>
  import { todo, todos, count, addTodo, error } from "./stores";
</script>

<div>
    <input type="text" bind:value={$todo.text} />
        {#if $error}
            <span class="error">{$error}</span>
        {/if}
    <button on:click={addTodo}>Add Todo</button>
<!-- show todo items -->
</div>

stores.js

import { writable, derived, get } from "svelte/store";

export const todo = writable({ text: "", completed: false });
export const todos = writable([{ text: "Learn Svelte", completed: false }]);

const formState = writable({ status: "idle" });

export const addTodo = () => {
  formState.set({ status: "submitted" });
  let _error = get(error);
  if (!_error) {
    let _todo = get(todo);
    todos.update((todos) => {
      todos.push(_todo);
      todo.update(() => ({ text: "", completed: false }));
      return todos;
    });
    formState.set({ status: "idle" });
  }
};

// 省略其他代码...

export const error = derived(todo, todo => {
  if (get(formState).status === "submitted") {
    if (!todo.text.trim()) {
      return "Please enter a task";
    } else if (todo.text.length < 3) {
      return "Todo must be at least 3 characters long";
    }
    return "";
  }
});

问题原因

  1. 派生store依赖缺失:error派生store仅声明依赖todo,但内部逻辑实际依赖formState的状态。当formState从idle变为submitted时,不会触发error的重新计算,此时get(error)拿到的还是旧值(undefined)。
  2. 同步获取store值的时序问题:在addTodo中,设置formState为submitted后立刻调用get(error),此时error还未完成重新计算,导致判断!_error为true,执行了添加空todo的逻辑。
  3. 验证触发滞后:只有当后续todo被清空(todo.update)时,error才会因为todo的变化重新计算,此时才返回错误信息,但空todo已经被添加到列表中。

解决方案

1. 修正派生store的依赖

让error同时依赖todo和formState,确保两者任一变化都会触发验证逻辑:

export const error = derived([todo, formState], ([$todo, $formState]) => {
  if ($formState.status === "submitted") {
    if (!$todo.text.trim()) {
      return "请输入任务内容";
    } else if ($todo.text.length < 3) {
      return "任务内容至少需要3个字符";
    }
    return "";
  }
  return undefined;
});

2. 调整addTodo的验证逻辑

避免同步get(error),改为直接在函数内完成验证,逻辑更清晰:

export const addTodo = () => {
  formState.set({ status: "submitted" });
  
  const currentTodo = get(todo);
  let validationError = "";
  if (!currentTodo.text.trim()) {
    validationError = "请输入任务内容";
  } else if (currentTodo.text.length < 3) {
    validationError = "任务内容至少需要3个字符";
  }

  if (!validationError) {
    todos.update(todos => [...todos, currentTodo]);
    todo.set({ text: "", completed: false });
    formState.set({ status: "idle" });
  }
};

内容的提问来源于stack exchange,提问作者Austin Walela

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 12:33:19