S
SolidJS•4mo ago
goe1980

Is there any secure alternative to createEffect?

About the following statement on createEffect documentation:
"Effects are meant primarily for side effects that read but don't write to the reactive system: it's best to avoid setting signals in effects, which without care can cause additional rendering or even infinite effect loops. Instead, prefer using createMemo to compute new values that depend on other reactive values, so the reactive system knows what depends on what, and can optimize accordingly."
I get the point on the "best to avoid setting signals" inside a createEffect, but that's precisely what I need to do. Is there any other solid primitive to run my effect securely to avoid infinite loops. Your suggestion on createMemo does not fit my use case. My effect is the following: createEffect(() => { options().length > 0 ? openSelect() : closeSelect() }) Thank you
25 Replies
deluksic
deluksic•4mo ago
Solid Primitives
A library of high-quality primitives that extend SolidJS reactivity
lxsmnsyc
lxsmnsyc•4mo ago
it's actually safe to update signals in an effect. The reason there was that "warning" is to prevent people from doing an accidental update recursion, where an effect might be indirectly tracking a signal that it is supposed to update.
deluksic
deluksic•4mo ago
Update recursions are pretty bad, but isn't the whole point of avoiding signal updates in effects the fact that they trigger rendering twice? Also when dealing with transitions, effects dont run until the end of the transition, whereas memos run immediately.
lxsmnsyc
lxsmnsyc•4mo ago
yeah it has nothing to do with rendering the template on their own is a completely independent effect. If anything, re-rendering is just a byproduct of the recursion
deluksic
deluksic•4mo ago
Oh I see now what you're saying with update recursion. My brain went to infinite loops for some reason, but ofc recursion can stop and still be bad đź‘Ť I mentioned rendering simply because that's by far the most common effect, but you're right, nothing to do with rendering.
goe1980
goe1980•4mo ago
Thank you for your suggestion, but in that case I'll not have a setter for "open" because it is a derived value from the options signal (which is made with createResource). I need the setter so I can use it on other events like input focus and blur.Don't know if I'm doing this right, but that's how I see the problem. Thank you all for your help. I guess I'll use createEffect carefully trying to avoid any circular references. After a few attempt to re-wire things I came up with a cleaner solution and avoid using createEffect. I'll share my solution, in the hope to help someone rethinking their signal dependencies.
function MyComponent(props) {
const options = props.optionsResource
const [focused, setFocus] = createSignal(false)

const opened = createMemo(() => !!options() && options().length > 0 && focused())

return (
<div>
<input onBlur={() => setFocus(false)} onFocus={() => setFocus(true)} />
<div class={setClassesWhen('list', opened, 'is-open is-focused')} role="listbox">
<For each={options()}>{(value, idx) => <div data-id={idx()}>{value}</div>}</For>
</div>
</div>
)
}
function MyComponent(props) {
const options = props.optionsResource
const [focused, setFocus] = createSignal(false)

const opened = createMemo(() => !!options() && options().length > 0 && focused())

return (
<div>
<input onBlur={() => setFocus(false)} onFocus={() => setFocus(true)} />
<div class={setClassesWhen('list', opened, 'is-open is-focused')} role="listbox">
<For each={options()}>{(value, idx) => <div data-id={idx()}>{value}</div>}</For>
</div>
</div>
)
}
bigmistqke
bigmistqke•4mo ago
you can format block of code with
you can remove that `createMemo`, you should only use memo if you are doing some computationally expensive stuff.

`const options = props.optionsResource` will not be reactive.

If you want a value to be reactive you should only access it in effectful/reactive places (like `createEffect`, `createMemo` or `jsx`), it's for that same reason that destructuring props is an anti-pattern in solidjs.
a, I see that you are calling it, so it's presumably a signal you are passing.

In that case it will work, but it's more conventional (and less error-prone) to instead call the signal and access props only in effectful enviroments (like mentioned above).
you can remove that `createMemo`, you should only use memo if you are doing some computationally expensive stuff.

`const options = props.optionsResource` will not be reactive.

If you want a value to be reactive you should only access it in effectful/reactive places (like `createEffect`, `createMemo` or `jsx`), it's for that same reason that destructuring props is an anti-pattern in solidjs.
a, I see that you are calling it, so it's presumably a signal you are passing.

In that case it will work, but it's more conventional (and less error-prone) to instead call the signal and access props only in effectful enviroments (like mentioned above).
tsx <MyComponents options={optionsSignal()}/>
the idea being that you than can either call a signal or just pass a static object and everything will JustWork™
something like
the idea being that you than can either call a signal or just pass a static object and everything will JustWork™
something like
tsx function MyComponent(props) { const [focused, setFocus] = createSignal(false) const opened = () => props.options && props.options.length > 0 && focused() return ( <div> <input onBlur={() => setFocus(false)} onFocus={() => setFocus(true)} /> <div class={setClassesWhen('list', opened, 'is-open is-focused')} role="listbox"> <For each={props.options}>{(value, idx) => <div data-id={idx()}>{value}</div>}</For> </div> </div> ) } <Suspense> <MyComponent options={optionsResource()}/> </Suspense> `` could u show implementation of setClassesWhen`? probably can be simplified too.
goe1980
goe1980•4mo ago
Ty for the review Just one thing. If you use optionsResource() as a prop, what's the problem on destructuring it inside the component? It's just a value, it will make no harm to the solid reactive system, right?
bigmistqke
bigmistqke•4mo ago
you mean your original approach?
goe1980
goe1980•4mo ago
No, I mean your review
bigmistqke
bigmistqke•4mo ago
your original approach would have been reacting when the resource resolves. if you would destructure inside the component in my example, the component would not be reacting on the changes.
bigmistqke
bigmistqke•4mo ago
to get an intuition why that is the case, i highly recommend watching https://www.youtube.com/watch?v=cELFZQAMdhQ
SolidJS
YouTube
Intro to SolidJS reactivity (in 5 minutes)
An introduction video that walks you through Solid's reactivity in under 5 minutes.
goe1980
goe1980•4mo ago
But you're calling it
<Suspense>
<MyComponent options={optionsResource()}/>
</Suspense>
<Suspense>
<MyComponent options={optionsResource()}/>
</Suspense>
bigmistqke
bigmistqke•4mo ago
you talk about
function MyComponent({options}) {
...
}
function MyComponent({options}) {
...
}
right?
goe1980
goe1980•4mo ago
My doubt is that, if you're calling "optionsResource()" it will be a value not a signal, what am I missing here?
bigmistqke
bigmistqke•4mo ago
the trick is that props are getters so it's like
{
get options(){
return optionsResource()
}
}
{
get options(){
return optionsResource()
}
}
bigmistqke
bigmistqke•4mo ago
the playground is handy if you want to know more about the props-transform.
No description
bigmistqke
bigmistqke•4mo ago
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
bigmistqke
bigmistqke•4mo ago
so when you do props.options you are actually calling a function, which is why you should only access the prop in effectful places and not destructure
goe1980
goe1980•4mo ago
hummm, I'm not seeing the props as getters on the playground... IDK
goe1980
goe1980•4mo ago
No description
goe1980
goe1980•4mo ago
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
goe1980
goe1980•4mo ago
ok, now I see it, ty đź‘Ť
bigmistqke
bigmistqke•4mo ago
if you press the output-tab you can see the result of the compilation
goe1980
goe1980•4mo ago
Thank you for the enlightenment guys!