SvelteKit表单操作和更新UI

huangapple go评论107阅读模式
英文:

SvelteKit Form actions and update UI

问题

我是初学者,正在尝试使用SvelteKit构建一个待办事项应用程序。这个问题关注的是我遇到的问题,同时也在询问数据获取和UI更新的逻辑是否正确。

我的表单如下:

<form
      action="?/create"
      method="POST"
      class="flex flex-col gap-5 justify-center items-center w-2/3 mx-auto"
      use:enhance
    >
      <div class="w-2/3">
        <label class="block text-sm text-gray-500" for="todo"> Title </label>
        <input
          class="border border-gray-300 w-full rounded-md shadow-sm hover:border-gray-400 focus:outline-none focus:border-gray-500 transition duration-100 ease-linear p-1 text-gray-700"
          type="text"
          name="title"
          bind:value={title}
        />
      </div>
      <div class="w-2/3">
        <label class="block text-sm text-gray-500" for="todo">
          Description
        </label>
        <textarea
          rows="4"
          class="w-full border border-gray-300 rounded-md shadow-sm hover:border-gray-400 focus:outline-none focus:border-gray-500 transition duration-100 ease-linear p-1 text-gray-700"
          name="desc"
          bind:value={desc}
        />
      </div>
      <div>
        <button
          class="bg-blue-500 text-white px-8 py-2 rounded-md font-semibold text-lg hover:bg-blue-600 transition duration-100 shadow-xl"
        >
          Create
        </button>
      </div>
    </form>

在+page.server.js中,我这样捕获表单操作:

export const actions = {
  create: async ({ cookies, request }) => {
    const data = await request.formData();
    if (data.get("title").length === 0) {
      return fail(400, {
        error: true,
        message: "Title can't be empty",
      });
    }
    if (data.get("desc").length === 0) {
      return fail(400, {
        error: true,
        message: "Description can't be empty",
      });
    }
    const todo = {
      title: data.get("title"),
      description: data.get("desc"),
    };
    try {
      const newTodos = await createTodo(todo);
      todosStore.set(newTodos);
    } catch (err) {
      return fail(422, {
        description: "Something went wrong",
      });
    }
  },
};

createTodo函数如下:

export const createTodo = async (todo) => {
  try {
    const todoRes = await db.collection("ToDo").insertOne({
      todo,
    });
    const newTodos = await getTodos();
    return newTodos;
  } catch (err) {
    console.log(err);
  }
};

然后我在page.svelte文件中订阅了todosStore并渲染了待办事项列表:

 import { todosStore } from "../stores/todoStore.js";

 let todos = $todosStore;
 <ToDoList {todos} />

虽然我向后端发送了POST请求,我的新待办事项已经正确添加到数据库,并且函数也正常工作,但我在UI上没有看到更改。

我的代码有什么问题?这是否是在SvelteKit应用程序中应用这种逻辑的正确方式?

谢谢。

英文:

I am a beginner with SvelteKit and trying to build a todo app. This question focuses on the following problem I have, but also asking if it's the correct logic to do data fetching and UI update.

My form is this:

 &lt;form
      action=&quot;?/create&quot;
      method=&quot;POST&quot;
      class=&quot;flex flex-col gap-5 justify-center items-center w-2/3 mx-auto&quot;
      use:enhance
    &gt;
      &lt;div class=&quot;w-2/3&quot;&gt;
        &lt;label class=&quot;block text-sm text-gray-500&quot; for=&quot;todo&quot;&gt; Title &lt;/label&gt;
        &lt;input
          class=&quot;border border-gray-300 w-full rounded-md shadow-sm hover:border-gray-400 focus:outline-none focus:border-gray-500 transition duration-100 ease-linear p-1 text-gray-700&quot;
          type=&quot;text&quot;
          name=&quot;title&quot;
          bind:value={title}
        /&gt;
      &lt;/div&gt;
      &lt;div class=&quot;w-2/3&quot;&gt;
        &lt;label class=&quot;block text-sm text-gray-500&quot; for=&quot;todo&quot;&gt;
          Description
        &lt;/label&gt;
        &lt;textarea
          rows=&quot;4&quot;
          class=&quot;w-full border border-gray-300 rounded-md shadow-sm hover:border-gray-400 focus:outline-none focus:border-gray-500 transition duration-100 ease-linear p-1 text-gray-700&quot;
          name=&quot;desc&quot;
          bind:value={desc}
        /&gt;
      &lt;/div&gt;
      &lt;div&gt;
        &lt;button
          class=&quot;bg-blue-500 text-white px-8 py-2 rounded-md font-semibold text-lg hover:bg-blue-600 transition duration-100 shadow-xl&quot;
        &gt;
          Create
        &lt;/button&gt;
      &lt;/div&gt;
    &lt;/form&gt;

On the +page.server.js I catch the form action like so:

export const actions = {
  create: async ({ cookies, request }) =&gt; {
    const data = await request.formData();
    if (data.get(&quot;title&quot;).length === 0) {
      return fail(400, {
        error: true,
        message: &quot;Title can&#39;t be empty&quot;,
      });
    }
    if (data.get(&quot;desc&quot;).length === 0) {
      return fail(400, {
        error: true,
        message: &quot;Description can&#39;t be empty&quot;,
      });
    }
    const todo = {
      title: data.get(&quot;title&quot;),
      description: data.get(&quot;desc&quot;),
    };
    try {
      const newTodos = await createTodo(todo);
      todosStore.set(newTodos);
    } catch (err) {
      return fail(422, {
        description: &quot;Something went wrong&quot;,
      });
    }
  },
};

The createTodo function is the following:

export const createTodo = async (todo) =&gt; {
  try {
    const todoRes = await db.collection(&quot;ToDo&quot;).insertOne({
      todo,
    });
    const newTodos = await getTodos();
    return newTodos;
  } catch (err) {
    console.log(err);
  }
};

I then subscribe to the todosStore on my page.svelte file and render a list of todos like this:

 import { todosStore } from &quot;../stores/todoStore.js&quot;;

 let todos = $todosStore;
 &lt;ToDoList {todos} /&gt;

While I do send the POST request to the backend and my new todo is correctly added to the database and the function also does its work, I do not see the change on my UI.

What is the problem with my code? Also is this the correct way to apply this kind of logic in SvelteKit apps?

Thank you.

答案1

得分: 3

不应在服务器上使用存储。

数据不会自动传输,服务器上的存储引用与客户端完全独立。

您的操作应返回 todo 对象,然后将其传递给+page.svelte组件的form属性。如果您需要以类似本例的方式对返回的数据进行操作,您可以enhance添加参数以拦截返回的数据,例如触发一个项目已添加事件或将项目添加到全局存储。

示例:

<form use:enhance={onSubmit}>
const onSubmit = () => {
    return ({ result, update }) => {
        if (result.type === "success") {
            const todo = result.data;
            console.log("新待办事项", todo);
        }
        else {
            update();
        }
    }
}

另一种方法是使用数据加载。在表单提交时,页面的data属性将自动重新加载,因此,如果您有一个从数据库中获取所有项目并将页面数据传递给列表组件的load函数,它将自动更新。

英文:

You cannot/should not use stores on the server.

The data will not be magically transferred, any store reference on the server is a completely separate instance from the client.

Your action should return the todo-object, which will then be passed to the form property of the +page.svelte component. If you need to imperatively interact with the returned data as in this case, you can add a parameter to enhance to intercept the return data and e.g. fire an event that an item has been added or add the item to a global store.

Example:

&lt;form use:enhance={onSubmit}&gt;
const onSubmit = () =&gt; {
    return ({ result, update }) =&gt; {
        if (result.type === &quot;success&quot;) {
            const todo = result.data;
            console.log(&quot;New todo&quot;, todo);
        }
        else {
            update();
        }
    }
}

An alternative to this would be using data loading. On form submission the data property of the page will automatically reload, so if you have a load function that gets all items from the DB and the page data is passed to the list component, it will update automatically.

huangapple
  • 本文由 发表于 2023年3月3日 18:48:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/75626086.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定