最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - SvelteKit fetching on the server and updating the writable store - Stack Overflow

programmeradmin1浏览0评论

I was wondering what is the best way to do data fetching in SvelteKit since I ran into the following problem on my app.

I have a writable store like so:

import { writable } from "svelte/store";

export const todosStore = writable();

As you see I have no initial value on my store. Then on the "+page.server.js" file I do my data fetching logic:

export async function load() {
  // fetch the todos on the server
  await getTodos();

  return {};
}
export const getTodos = async () => {
  const todos = await db.collection("ToDo").find().toArray();
  let serializedTodos = todos.map(({ _id, ...rest }) => {
    return {
      ...rest,
      id: _id.toString(),
    };
  });
  todosStore.update(() => serializedTodos);
};

I then loop over the todos from the store and display a list of items. The problem is, on the first render on the browser I get the following error:

[HMR][Svelte] unrecoverable HMR error in <ToDoList>: next update will trigger a full reload
Uncaught (in promise) Error: {#each} only iterates over array-like objects.

It kinda makes sense, since the store has no initial value. I then decide to change the original value of my store to an empty array (since the fetched data e into an array), like so:

export const todosStore = writable([]);

When I make this change, the UI renders with the correct state (the todos store has the fetched data) and after a short time, the data disappear and I get an empty array.

Is this the expected behavior from SvelteKit? What is the correct way to do data fetching if I need to fetch on the server (I have API keys on the db call, so I can't fetch on the client since Vite throws me an error).

I was wondering what is the best way to do data fetching in SvelteKit since I ran into the following problem on my app.

I have a writable store like so:

import { writable } from "svelte/store";

export const todosStore = writable();

As you see I have no initial value on my store. Then on the "+page.server.js" file I do my data fetching logic:

export async function load() {
  // fetch the todos on the server
  await getTodos();

  return {};
}
export const getTodos = async () => {
  const todos = await db.collection("ToDo").find().toArray();
  let serializedTodos = todos.map(({ _id, ...rest }) => {
    return {
      ...rest,
      id: _id.toString(),
    };
  });
  todosStore.update(() => serializedTodos);
};

I then loop over the todos from the store and display a list of items. The problem is, on the first render on the browser I get the following error:

[HMR][Svelte] unrecoverable HMR error in <ToDoList>: next update will trigger a full reload
Uncaught (in promise) Error: {#each} only iterates over array-like objects.

It kinda makes sense, since the store has no initial value. I then decide to change the original value of my store to an empty array (since the fetched data e into an array), like so:

export const todosStore = writable([]);

When I make this change, the UI renders with the correct state (the todos store has the fetched data) and after a short time, the data disappear and I get an empty array.

Is this the expected behavior from SvelteKit? What is the correct way to do data fetching if I need to fetch on the server (I have API keys on the db call, so I can't fetch on the client since Vite throws me an error).

Share Improve this question edited Sep 23, 2024 at 22:33 brunnerh 186k30 gold badges357 silver badges430 bronze badges asked Mar 2, 2023 at 14:33 Anargyros StylidisAnargyros Stylidis 2791 gold badge7 silver badges16 bronze badges 3
  • Do not screenshot code/errors. Insert that as text and format it. – brunnerh Commented Mar 2, 2023 at 15:05
  • I agree but since this is a pretty standard use case on any app, my question is more informative than technical. I guess anyone who used SvelteKit came across this kind of issue. – Anargyros Stylidis Commented Mar 2, 2023 at 15:36
  • What the question is about is pletely irrelevant in regards to what its formatting should be like. – brunnerh Commented Mar 2, 2023 at 15:56
Add a ment  | 

2 Answers 2

Reset to default 7

This is due to a misunderstanding of how SvelteKit works.

In short, pages are rendered on the server (SSR) and the markup together with a payload containing the data returned from load is send to the client. In order to add all interactivity and things, the client will 'hydrate' the page using the received data, meaning that it will rebuild the page, but keeping in place the parts already existing. A side effect of this is that anything that was rendered on the server but is not being rendered by the client flickers as it is first there and then not anymore.

How does this apply to your case ? Well, simply by the fact that there is no shared state between server and client, the only thing that is passed down is what is returned from the load function, so while you populated the store server side, it will still be empty client side.

As the other answer also says, a solution is to pass your todos as data from the load function and then initialize the store with it on the client instead:

export let data; // data es from load
todoStore.set(data.todos)

On a final note, it's worth mentioning here that while your store is not shared between client and server, it will be shared among different requests to the server, meaning that using global stores like in your code has a big risk of leaking content from one user to the other, where I would see in a flicker the content that was in the store for your request.

The store concept is on the client side, The DB calls can (should) happen on the server side where you control your env variables.

Option 1: On the +page.server.js you pass the data to the client side when the page loads and then on the client side you may use the store to have it on the client side or use Websockets or Server-sent events.

Option 2: Make a +server.js API route to get data and have the store updated on the client side and use a logic suitable to save on API calls.

I have made a demo here

发布评论

评论列表(0)

  1. 暂无评论