S
SolidJS5mo ago
Carter

How can I persist state across page refreshes?

export const [fourCountryQuestion, setFourCountryQuestion] = createStore(getRandomQuestionData())
export const [fourCountryQuestion, setFourCountryQuestion] = createStore(getRandomQuestionData())
31 Replies
Carter
CarterOP5mo ago
is there a way for state to persist across page reloads? I'm trying to make a flags quiz app. it works but as soon as I reload the page. the data seems to go out of sync
REEEEE
REEEEE5mo ago
Localstorage
Brendonovich
Brendonovich5mo ago
Solid Primitives
A library of high-quality primitives that extend SolidJS reactivity
Carter
CarterOP5mo ago
it still changes when I reload the page. when I reload the page it always goes to a certain flag
Madaxen86
Madaxen865mo ago
If you are using SSR you should probably switch to cookieStorage because localstorage and sessionstorage are not available on the server.
Carter
CarterOP5mo ago
I'm having trouble rending my state as well:
export default function FourCountryQuiz() {
const [questionData, setQuestionData] = createSignal(getRandomQuestionData());
const [score, setScore] = createSignal(0)

createEffect(() => {
console.log(questionData().correctFlag.name);
})
return (
<div class="flex flex-row">


<div class="p-2 border rounded basis-1/2">
<img class="w-96 shadow-md border" src={questionData().correctFlag.img}></img>

<div class="grid grid-cols-2 gap-2 py-2">
<For each={questionData().choices}>{(flag, _) =>
<button class="p-2 border rounded" onclick={() => {
if (flag.name === questionData().correctFlag.name) {
console.log('changed question')

alert("right! current score: " + score())
setScore(score() + 1);
setQuestionData(getRandomQuestionData())

} else {
alert('wrong!')
}
}}>
{flag.name}
</button>
}</For>

</div>

</div>

<div class="border p-4 rounded-full">
{score()}
</div>
</div>
export default function FourCountryQuiz() {
const [questionData, setQuestionData] = createSignal(getRandomQuestionData());
const [score, setScore] = createSignal(0)

createEffect(() => {
console.log(questionData().correctFlag.name);
})
return (
<div class="flex flex-row">


<div class="p-2 border rounded basis-1/2">
<img class="w-96 shadow-md border" src={questionData().correctFlag.img}></img>

<div class="grid grid-cols-2 gap-2 py-2">
<For each={questionData().choices}>{(flag, _) =>
<button class="p-2 border rounded" onclick={() => {
if (flag.name === questionData().correctFlag.name) {
console.log('changed question')

alert("right! current score: " + score())
setScore(score() + 1);
setQuestionData(getRandomQuestionData())

} else {
alert('wrong!')
}
}}>
{flag.name}
</button>
}</For>

</div>

</div>

<div class="border p-4 rounded-full">
{score()}
</div>
</div>
I'm just trying to make a simple flag triva question but it's displaying the wrong flag when I reload the page how is that even possible. like the flag being displayed in img tag is not the same flag printed by the createEffect I changed it a little bit. this works as expected. Now how can I just get it to stay the heck the same across page reloads?
const [questionData, setQuestionData] = createSignal<FourCountryQuestionData>({
correctFlag: { name: '', continent: '', description: '', img: '' },
choices: []
});
const [score, setScore] = createSignal(0)

createEffect(() => {
console.log(questionData().correctFlag.name);
})
onMount(() => {
setQuestionData(getRandomQuestionData())
})
return (
<div class="flex flex-row">


<div class="p-2 border rounded basis-1/2">
<img class="w-96 shadow-md border" src={questionData().correctFlag.img}></img>

<div class="grid grid-cols-2 gap-2 py-2">
<For each={questionData().choices}>{(flag, _) =>
<button class="p-2 border rounded" onclick={() => {
if (flag.name === questionData().correctFlag.name) {
console.log('changed question')

setScore(score() + 1);
alert("right! current score: " + score())
setQuestionData(getRandomQuestionData())

} else {
alert('wrong!')
}
}}>
{flag.name}
</button>
}</For>

</div>

</div>

<div class="border p-4 rounded-full">
{score()}
</div>
</div>
}
const [questionData, setQuestionData] = createSignal<FourCountryQuestionData>({
correctFlag: { name: '', continent: '', description: '', img: '' },
choices: []
});
const [score, setScore] = createSignal(0)

createEffect(() => {
console.log(questionData().correctFlag.name);
})
onMount(() => {
setQuestionData(getRandomQuestionData())
})
return (
<div class="flex flex-row">


<div class="p-2 border rounded basis-1/2">
<img class="w-96 shadow-md border" src={questionData().correctFlag.img}></img>

<div class="grid grid-cols-2 gap-2 py-2">
<For each={questionData().choices}>{(flag, _) =>
<button class="p-2 border rounded" onclick={() => {
if (flag.name === questionData().correctFlag.name) {
console.log('changed question')

setScore(score() + 1);
alert("right! current score: " + score())
setQuestionData(getRandomQuestionData())

} else {
alert('wrong!')
}
}}>
{flag.name}
</button>
}</For>

</div>

</div>

<div class="border p-4 rounded-full">
{score()}
</div>
</div>
}
REEEEE
REEEEE5mo ago
Are you persisting the signal data into storage?
Carter
CarterOP5mo ago
nvm this is way easier than I though just doing it manually I was trying to do it using makePersisted but I couldn't figure it out should I just onMount for persisting it locally?
REEEEE
REEEEE5mo ago
You can, but changes made to the signal after the mount won't be persisted
Carter
CarterOP5mo ago
so what is the alternative?
REEEEE
REEEEE5mo ago
do the persisting in a createEffect that listens to the signal
Carter
CarterOP5mo ago
should I add the items in onMount then update them in createEffect?
REEEEE
REEEEE5mo ago
createEffect will run on mount as well
Carter
CarterOP5mo ago
so createEffect isn't running after each update to the signals. why not?
REEEEE
REEEEE5mo ago
what do you mean? createEffect runs on mount and whenever a signal read inside of it changes
Carter
CarterOP5mo ago
if you look at the callback on my button you'll see I changed one of the signals but my createEffect is not being called. I made sure to put log calls in each and they are only being called when I first load the page
REEEEE
REEEEE5mo ago
Do you have any code you can show for your createEffect?
Carter
CarterOP5mo ago
const [questionData, setQuestionData] = createSignal<FourCountryQuestionData>({
correctFlag: { name: '', continent: '', description: '', img: '' },
choices: []
});
const [score, setScore] = createSignal(0)

createEffect(() => {
console.log('createEffect')
})

onMount(() => {

console.log('onMount')

const storedQuestionData = localStorage.getItem("fourCountryQuestion");
if (storedQuestionData) {
console.log('getting questionData')
setQuestionData(JSON.parse(storedQuestionData));
} else {

setQuestionData(getRandomQuestionData())
localStorage.setItem("fourCountryQuestion", JSON.stringify(questionData()));
}
const storedScore = localStorage.getItem("score")
if (storedScore) {
console.log('getting score');
setScore(JSON.parse(storedScore))
} else {

setScore(0)
localStorage.setItem("score", JSON.stringify(score()))
}
})
return (
<div class="flex flex-row">

<div class="p-2 border rounded basis-1/2">
<img class="w-96 shadow-md border" src={questionData().correctFlag.img}></img>

<div class="grid grid-cols-2 gap-2 py-2">
<For each={questionData().choices}>{(flag, _) =>
<button class="p-2 border rounded" onclick={() => {
if (flag.name === questionData().correctFlag.name) {

setScore(score() + 1);
alert("right! current score: " + score())
setQuestionData(getRandomQuestionData())

localStorage.setItem("score", JSON.stringify(score()))
localStorage.setItem("fourCountryQuestion", JSON.stringify(questionData()))
} else {
alert('wrong!')
}
}}>
{flag.name}
</button>
}</For>

</div>

</div>

<div class="border p-4 rounded-full">
{score()}
</div>
</div>
const [questionData, setQuestionData] = createSignal<FourCountryQuestionData>({
correctFlag: { name: '', continent: '', description: '', img: '' },
choices: []
});
const [score, setScore] = createSignal(0)

createEffect(() => {
console.log('createEffect')
})

onMount(() => {

console.log('onMount')

const storedQuestionData = localStorage.getItem("fourCountryQuestion");
if (storedQuestionData) {
console.log('getting questionData')
setQuestionData(JSON.parse(storedQuestionData));
} else {

setQuestionData(getRandomQuestionData())
localStorage.setItem("fourCountryQuestion", JSON.stringify(questionData()));
}
const storedScore = localStorage.getItem("score")
if (storedScore) {
console.log('getting score');
setScore(JSON.parse(storedScore))
} else {

setScore(0)
localStorage.setItem("score", JSON.stringify(score()))
}
})
return (
<div class="flex flex-row">

<div class="p-2 border rounded basis-1/2">
<img class="w-96 shadow-md border" src={questionData().correctFlag.img}></img>

<div class="grid grid-cols-2 gap-2 py-2">
<For each={questionData().choices}>{(flag, _) =>
<button class="p-2 border rounded" onclick={() => {
if (flag.name === questionData().correctFlag.name) {

setScore(score() + 1);
alert("right! current score: " + score())
setQuestionData(getRandomQuestionData())

localStorage.setItem("score", JSON.stringify(score()))
localStorage.setItem("fourCountryQuestion", JSON.stringify(questionData()))
} else {
alert('wrong!')
}
}}>
{flag.name}
</button>
}</For>

</div>

</div>

<div class="border p-4 rounded-full">
{score()}
</div>
</div>
this right now works but the issue is I need to update the storage in the callback
REEEEE
REEEEE5mo ago
your effect isn't listening to the signal
Carter
CarterOP5mo ago
how do I do that? oh I see what you're saying
REEEEE
REEEEE5mo ago
createEffect(() => {
localStorage.setItem("fourCountryQuestion", JSON.stringify(questionData()));
localStorage.setItem("score", JSON.stringify(score()))
})

onMount(() => {

console.log('onMount')

const storedQuestionData = localStorage.getItem("fourCountryQuestion");
if (storedQuestionData) {
console.log('getting questionData')
setQuestionData(JSON.parse(storedQuestionData));
} else {
setQuestionData(getRandomQuestionData())
}
const storedScore = localStorage.getItem("score")
if (storedScore) {
console.log('getting score');
setScore(JSON.parse(storedScore))
} else {
setScore(0)
}
})
createEffect(() => {
localStorage.setItem("fourCountryQuestion", JSON.stringify(questionData()));
localStorage.setItem("score", JSON.stringify(score()))
})

onMount(() => {

console.log('onMount')

const storedQuestionData = localStorage.getItem("fourCountryQuestion");
if (storedQuestionData) {
console.log('getting questionData')
setQuestionData(JSON.parse(storedQuestionData));
} else {
setQuestionData(getRandomQuestionData())
}
const storedScore = localStorage.getItem("score")
if (storedScore) {
console.log('getting score');
setScore(JSON.parse(storedScore))
} else {
setScore(0)
}
})
You can do this
Carter
CarterOP5mo ago
yes but now it's just persisting the initial values
REEEEE
REEEEE5mo ago
Wym?
Carter
CarterOP5mo ago
No description
Carter
CarterOP5mo ago
when createEffect is called it persists the initial values and so nothing is displayed
REEEEE
REEEEE5mo ago
When do you want to persist it the values? The effect will call setItem whenever the signals change
Carter
CarterOP5mo ago
well the logic in onMount should be called once, then for each change to the values we would persist it the issue is createEffect is called at the beginning once as well
REEEEE
REEEEE5mo ago
Actually here this will be better
createEffect(on(questionData, () => {
localStorage.setItem("fourCountryQuestion", JSON.stringify(questionData()));
}, {defer: true}))

createEffect(on(score, () => {
localStorage.setItem("score", JSON.stringify(score()))
}, {defer: true}))
createEffect(on(questionData, () => {
localStorage.setItem("fourCountryQuestion", JSON.stringify(questionData()));
}, {defer: true}))

createEffect(on(score, () => {
localStorage.setItem("score", JSON.stringify(score()))
}, {defer: true}))
Defer will stop it from running on mount
Carter
CarterOP5mo ago
okay thank you so much that worked
Carter
CarterOP5mo ago
No description
Carter
CarterOP5mo ago
I see scripts assets and children where are scripts and assets located at?
Want results from more Discord servers?
Add your server