Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

persisted() returns undefined first time it's accessed, even when initial is set #81

Open
FluffyDiscord opened this issue Sep 4, 2023 · 6 comments

Comments

@FluffyDiscord
Copy link

I have the following setup

export type LastLocation = {
    location: null|[number, number]
    state: "DENIED"|"ALLOWED"|"UNKNOWN"|"ASKED"
}

export const lastLocation = persisted<LastLocation>({
    location: null,
    state: "UNKNOWN",
}, "last-location", {
    storageType: "LOCAL_STORAGE",
})

which I then use in my component

<script lang="ts">
    import {lastLocation} from "./utils"

    if($lastLocation.state === "UNKNOWN") {
        // error
    }
</script>

The problem is, that the first time the store is initialized and saved to the local storage with it's default value, $lastLocation is undefined. I need to reload the store/page.
image

This line is the culprit https://github.com/square/svelte-store/blob/main/src/persisted/index.ts#L140

The initial value should be passed, NOT undefined

@FluffyDiscord FluffyDiscord changed the title persisted() returns undefined first time it's accessed, even when initialValue is set persisted() returns undefined first time it's accessed, even when initial is set Sep 4, 2023
@rafadess
Copy link

I have the same issue with persistent, it starts with undefined even though it has initial value.

Maybe, one way to fix it is passing the initial value to the thisStore writable. This way subscribe function will return the correct initial value.

let initialValue

if (isLoadable(initial)) {
 initialValue = await initial.load();
} else {
 initialValue = initial
}

const thisStore = writable<T>(initialValue, (set) => {
  initialSync = synchronize(set);
});

https://github.com/square/svelte-store/blob/44341f5166826982d947c9dd8bc63193911c8a74/src/persisted/index.ts#L140C3-L140C3

The if conditional could go into a dedicate function, since it is the same code inside of syncronize. Any way, this is just a possible solution. 😉

@based64-eth
Copy link

I have the same issue with persistent, it starts with undefined even though it has initial value.

Maybe, one way to fix it is passing the initial value to the thisStore writable. This way subscribe function will return the correct initial value.

let initialValue

if (isLoadable(initial)) {
 initialValue = await initial.load();
} else {
 initialValue = initial
}

const thisStore = writable<T>(initialValue, (set) => {
  initialSync = synchronize(set);
});

https://github.com/square/svelte-store/blob/44341f5166826982d947c9dd8bc63193911c8a74/src/persisted/index.ts#L140C3-L140C3

The if conditional could go into a dedicate function, since it is the same code inside of syncronize. Any way, this is just a possible solution. 😉

This is not an acceptable solution in the case that the initial value NEEDS to be equal to the value that the user has stored in localStorage.

@thanhnguyen2187
Copy link

Hi! I'm having the same problem. Is there any way to fix it?

@nikicat
Copy link

nikicat commented Apr 10, 2024

I have the same issue with persistent, it starts with undefined even though it has initial value.
Maybe, one way to fix it is passing the initial value to the thisStore writable. This way subscribe function will return the correct initial value.

let initialValue

if (isLoadable(initial)) {
 initialValue = await initial.load();
} else {
 initialValue = initial
}

const thisStore = writable<T>(initialValue, (set) => {
  initialSync = synchronize(set);
});

https://github.com/square/svelte-store/blob/44341f5166826982d947c9dd8bc63193911c8a74/src/persisted/index.ts#L140C3-L140C3
The if conditional could go into a dedicate function, since it is the same code inside of syncronize. Any way, this is just a possible solution. 😉

This is not an acceptable solution in the case that the initial value NEEDS to be equal to the value that the user has stored in localStorage.

But it's better than the current state.

@rafadess
Copy link

rafadess commented Apr 10, 2024

I have the same issue with persistent, it starts with undefined even though it has initial value.
Maybe, one way to fix it is passing the initial value to the thisStore writable. This way subscribe function will return the correct initial value.

let initialValue

if (isLoadable(initial)) {
 initialValue = await initial.load();
} else {
 initialValue = initial
}

const thisStore = writable<T>(initialValue, (set) => {
  initialSync = synchronize(set);
});

https://github.com/square/svelte-store/blob/44341f5166826982d947c9dd8bc63193911c8a74/src/persisted/index.ts#L140C3-L140C3
The if conditional could go into a dedicate function, since it is the same code inside of syncronize. Any way, this is just a possible solution. 😉

This is not an acceptable solution in the case that the initial value NEEDS to be equal to the value that the user has stored in localStorage.

Hunn, how about this then:

let initialValue
const storageKey = await getKey();
const stored = getStorageItem(storageKey);

if (stored) {
  initialValue = stored
} else {
  if (isLoadable(initial)) {
   initialValue = await initial.load();
  } else {
   initialValue = initial
  }
}


const thisStore = writable<T>(initialValue, (set) => {
  initialSync = synchronize(set);
});

I can make a PR with this, if the maintainers agree with.

@nikicat
Copy link

nikicat commented Apr 10, 2024

I've solved my case with such a wrapper

function fixPersisted<T>(initial: T, store: Writable<T>): Writable<T> {
  return {
    subscribe: (run: (value: any) => void, invalidate?) => {
      return store.subscribe((value: any) => {
	if (value !== undefined) {
	  run(value)
	} else {
	  run(initial)
	}
      }, invalidate)
    },
    set: store.set,
    update: store.update,
  }
}

It doesn't wait to load the persisted value and always returns the initial value on start.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants