S
SolidJS3mo ago
hannus

How can I make createEffect in SolidJS execute only when the dependency variable changes, and not wh

For example:
const [value, setValue] = createSignal<string>("")
createEffect(() => { localStorage.setItem("value", value()) })
const [value, setValue] = createSignal<string>("")
createEffect(() => { localStorage.setItem("value", value()) })
I want to save the value to localStorage only after modifying the value, but do nothing when it is initially created with the value "". I remember that in previous documentation, createEffect wouldn’t execute if the dependency variable was false or undefined. But it seems that this behavior has changed now.
11 Replies
bigmistqke
bigmistqke3mo ago
you could do something like
const [value, setValue] = createSignal<string>("")
let initialised = false
createEffect(() => {
if(!initialised){
initialised = true;
return;
}
localStorage.setItem("value", value())
})
const [value, setValue] = createSignal<string>("")
let initialised = false
createEffect(() => {
if(!initialised){
initialised = true;
return;
}
localStorage.setItem("value", value())
})
I remember that in previous documentation, createEffect wouldn’t execute if the dependency variable was false or undefined. But it seems that this behavior has changed now.
mm, i don't think this was ever the case. at least not for solid > 1.0
hannus
hannusOP3mo ago
Thanks. However, it doesn’t work. The effect doesn’t execute, not only during the initial run but also when the value is updated afterward.
bigmistqke
bigmistqke3mo ago
a je lol ur right, i m completely wrong my bad because it never accessed the signal the effect does not re-run when the signal updates you could do
const [value, setValue] = createSignal<string>("")
let initialised = false
createEffect(() => {
value();
if(!initialised){
initialised = true;
return;
}
localStorage.setItem("value", value())
})
const [value, setValue] = createSignal<string>("")
let initialised = false
createEffect(() => {
value();
if(!initialised){
initialised = true;
return;
}
localStorage.setItem("value", value())
})
or use on to explicitly subscribe to the signal:
const [value, setValue] = createSignal<string>("")
let initialised = false
createEffect(on(value, (value) => {
if(!initialised){
initialised = true;
return;
}
localStorage.setItem("value", value)
}))
const [value, setValue] = createSignal<string>("")
let initialised = false
createEffect(on(value, (value) => {
if(!initialised){
initialised = true;
return;
}
localStorage.setItem("value", value)
}))
hannus
hannusOP3mo ago
Thanks, it works. You’ve been a great help to me. If I have more than one signal to depend on, such as value() and title(), how should I handle it?
bigmistqke
bigmistqke3mo ago
you are welcome!
If I have more than one signal to depend on, such as value() and title(), how should I handle it?
you could either access them all before the conditional, or pass them to on:
const [value, setValue] = createSignal<string>("")
const [otherValue, setOtherValue] = createSignal<string>("")
let initialised = false
createEffect(on(() => [value(), otherValue()], ([value, otherValue]) => {
if(!initialised){
initialised = true;
return;
}
localStorage.setItem("value", value)
localStorage.setItem("otherValue", otherValue)
}))
const [value, setValue] = createSignal<string>("")
const [otherValue, setOtherValue] = createSignal<string>("")
let initialised = false
createEffect(on(() => [value(), otherValue()], ([value, otherValue]) => {
if(!initialised){
initialised = true;
return;
}
localStorage.setItem("value", value)
localStorage.setItem("otherValue", otherValue)
}))
hannus
hannusOP3mo ago
thanks a lot. I have never used on function, it seems like very useful. I appreciate
bigmistqke
bigmistqke3mo ago
now that i m thinking, mb a cleaner approach is
const [value, setValue] = createSignal<string | null>(null)
createEffect(() => {
if(value() !== null) localStorage.setItem("value", value())
})
return <input onInput={(e) => setValue(e.currentTarget.value)}/>
const [value, setValue] = createSignal<string | null>(null)
createEffect(() => {
if(value() !== null) localStorage.setItem("value", value())
})
return <input onInput={(e) => setValue(e.currentTarget.value)}/>
that way null is your initial value, and only when it is changed it will be updated in local-storage. then you don't have to keep a value around to track initisalisation and you don't have to do explicit dependency-arrays (like with on)
Andreas Roth
Andreas Roth3mo ago
(Maybe a bit late, but anyways): I think this pattern is a code smell. This directly points us to move the logic into the event handler...
const [value, internalSetValue] = createSignal("");
function setValue(newValue: string) {
localStorage.setItem("value", newValue);
internalSetValue(newValue);
}

// ...
const [value, internalSetValue] = createSignal("");
function setValue(newValue: string) {
localStorage.setItem("value", newValue);
internalSetValue(newValue);
}

// ...
Could also easily be wrapped into a "hook" so that internalSetValue isn't even available to the outside.
hannus
hannusOP3mo ago
thanks, it is very useful. I have updated my code by your advice, it's clear. Thanks a lot. I am going to try object by createStore later.
bigmistqke
bigmistqke3mo ago
true, this is probably the simplest and most robust solution
hannus
hannusOP3mo ago
cheers thanks, your advice is very useful. I believe this pattern could be used in more scenarios
Want results from more Discord servers?
Add your server