#why does this playground link re-render the outer component?
133 messages · Page 1 of 1 (latest)
you can have type safety without re-rendering the entire thing, but that's not implemented currently. I think it might ship in v1.7
Maybe though, there are talks about it saying that the signal got narrowed, but actually potentially return null to you, in which case it won't really be type-safe, just pretend to be
yeah but you changed the child also
maybe the entire child is being put into an effect because you are calling a function in it, I'm not entirely sure, the way Solid works in this regard is a bit of a mystery to me 🤣
It should work if you make drawChildren a component
Yeah, the way it's designed right now, it can't update without rerunning the drawChildren function. If drawChildren accepted an accessor instead, it might be a bit different
If it's of any consolation what I think you want (receiving a narrowed signal containing the last value that passed the Show) can be implemented today in userland, it's just not how the built-in Show works
I'm saying it might, but I don't actually think so because I think the most probable outcome is that Show will become fake-type-safe, you seem to want real-type-safe
For example:
- Fake: You give Show an Accessor<number | null>, and it passes your function a function that says it's an Accessor<number>, but it can actually return you null just the same, so really there's just a type assertion just the same, it's just done for you implicitly (which is even worse imo).
- Real: You give Show an Accessor<number | null>, and it passes your function a function that says it's an Accessor<number>, and there's nothing more to it, the function will always return
numberand never something else.
i don't really understand. i pass a show an Accessor<number | null> and it can pass my function an Accessor<number> but it's actually null?
No, I'm saying what is likely to happen is that you give show Accessor<number | null>, it gives you something that says it's Accessor<number>, but in reality it's Accessor<number | null>
In this code:
<Show when={arr()}>
What do you think Show is receiving as the value of its "when" prop?
If you are giving Show just Array<number>, and assuming that signals are the only thing that can notify us of updates (which is true), how is it possible that when you update the value of the arr signal with a new array we are notified of updates? The previous array we got before never changed, so where is this re-execution coming from?
A better way to put the question is this:
Eventually that Show component will be called as a function, what plain javascript code do you think that JSX is compiled to?
Well try to answer this question, do you think the plain javascript that will be compiled from that JSX is something like Show ({ when: arr() })?
You need to freshen up this aspect because I think it's crucial to understand how Solid actually works, which is not how TypeScript thinks the code you are writing works, crucially
in reality the actual code that will be executed is closer to this:
Show ({
get arr() {
return arr();
}
})
For what is worth I don't think Solid is usable for any interesting application without deeper understanding how it actually works. I don't think you need to understand everything, in fact I think understanding everything is basically impossible as a user in my opinion, there are too many details not documented anywhere, but things like "you are not really writing TypeScript" must be understood in order to use Solid correctly, in my opinion. If others are of different opinions I just have no idea how they can write production code that works 🤣 maybe it's possible, I don't know, I couldn't do it
yeah so it doesn't really work
like performance is part of the problem to solve here
if one doesn't care about performance then things like React without useMemo, useCallback, useEvent and what not may be simpler to use
I don't know exactly because it hasn't been finalized yet
this specific thing hasn't been finalized yet either, I don't think, or if it got finalized nobody told me
I think best case scenario your code will require some simple changes but other than that it will work correctly without re-renders. But most likely scenario with the same simple changes your code will work potentially without re-renders, but incorrectly. "Incorrectly" in the sense that Show will be lying to you, it will say that it will give you an accessor that will never return null or undefined, but it will, potentially, in some cases.
Like how Show works with a function passed as child and without the "keyed" prop, I don't know how it will work in v1.7
I don't know
Ryan had a poll about that https://twitter.com/RyanCarniato/status/1635677118188363781
Working on type-narrowed control flow for @solid_js. What's the expected log if the user switches to null before the timeout goes off?(w/o cleanup)
<Show when={user()}>{
narrowedUser => {
setTimeout(() =>
console.log(narrowedUser(), 4000));
}
}</Show>
there was some discussion in some channel here on discord, I don't remember which though
start reading from here #general message
it's like the function you are passing as a child is written inline
to avoid re-renders Show must give you a signal basically, or let's say "a getter to a signal", which is what the accessor is basically, so the code will require some changes to work as you want it to, but that's unavoidable
if it's not a function then you can't avoid the re-renders and you can't do it efficiently
it's basically impossible to have this "just work"
to have this working in reality the argument must be a function
which as I'm understanding it it will in v1.7
the question is whether the type of that function will be a lie or not, basically
and as I'm understanding it the most likely outcome is that it will be a lie
it's not necessary, the Show I use doesn't lie to me 🤣
the Show component I use doesn't cause unnecessary re-renders in its non-keyed form, and it doesn't give me a function that says it has a particular type while in practice it has a different type, the type it says it has is the correct one
it's not written for Solid
like I don't use Solid
Yeah it can be ported
It kinda is in my opinion 🤣 but there's one tricky bit here, my Show gives you a signal to the last user that passed the Show check, it's not kept in sync with the original user signal. Like if user is set to null in the feature the signal that Show gave you will still contain the last user that passed the check. Which I guess is something you can use to shoot yourself in the foot. The other alternative that still doesn't cause re-renders and that still doesn't lie to you is if the signal that Show gives you throws when read once the original user signal is set to null. Which seems easier to cause problems to me, though arguably safer in some way.
Ryan seems to be going for neither of those approaches, but instead for an alternative where the type of the function that Show gives is just incorrect, and fingers crossed I guess
But I'm not up to date on what the latest opinion on this is
You'd have to ask him, or wait for v1.7
yeah kind of
yeah it's a different signal
🤷♂️ I mean if you know how to cause a bug with that by writing reasonable code I'd like to see it
by writing unreasonable code one can cause bugs in all sorts of ways, so that scenario seems uninteresting to me
Yeah I said this in the messages I linked you, I think he was unsure about the solution to go for, because a truly obvious solution doesn't exist really. I think on one hand he doesn't want the non-keyed Show to cause re-renders, so he wants to solve this, but he doesn't like that reading the signal throws on read, he doesn't like too much the approach where a new signal is created because it's kinda disconnected from the original one, and he doesn't like too much the option where the type of signal that Show gives you is incorrect, though he doesn't really care too much about types so that seems the option he might be going for. But I don't want to put words in his mouth, that's just my understanding of the situation
if it throws you just never see the narrowedUser signal being null, so in some sense the type is correct because you always see a user object being returned to you, never null, though you don't see the null just because reading the signal blows up in your face 🤣
🤷♂️ that's the situation
we'll see what v1.7 will bring us
or you I guess 🤣
Well, the one and only thing to know about solid's compiler, is that ~all jsx expressions are lazified. So even though you passed arr(), what actually happens is that you passed arr, and arr is called when props.arr is accessed
This is pretty crucial to remember. I've seen a lot of bugs because people didn't realize this
There are other things to know imo, like how do spreads work? I don't really understand it entirely. I can't use spreads if I don't understand them
Perhaps, but you couldn't possibly write code like arr and expect it to work othwrwise
Yes, it rewrites the JSX. That's what a compiler is 😂
Oh sure, you could do that
yes, the same code compiled with just typescript, or with typescript + solid, is completely different some times
In that case, you'd also need to return a closure returning jsx from your components, instead of returning jsx from your components directly
But keep that in mind, and you absolutely can use solid that way
yeah 🤣 which is what I do in my code, much much simpler to understand, like you can't not understand it, you pass a signal you get a signal, if you think you got an array the code just will never work
If you're writing functions the way you are (they take arguments, not props), you absolutely should pass signals to the functions, not values
You can in theory, but I haven't actually seen evidence of that, like the way it works seems to be bordeline unusable, unless you use template literals perhaps, which I haven't tried
the crazy bit imo is that people can use Solid without knowing this. Like how is this not front and center in the docs? I don't understand it
However, Ryan chose this way because now you don't need to ever check if props.val is a signal or a value. You can just always assume that the value might be reactive, and don't need to check it is a function and call it
I 100% find it shocking that people can get beyond the basics without knowing this
to be clear value={value()} is not compiled to { value: value () }, which is what TS would compile it to, it's not compiled to { value: value } either, it's actually compiled to { get value () { return value () } }, like there's an hidden function call happening when you read props, which is why you shouldn't destructure them
My experience in real world solid has taught me that there's a lot people don't know about solid. I worked on an app where half the show components were keyed, and state couldn't be updated granularly in a lot of cases
Right, because destructuring means that you're accessing immediately
mind blowing
What's a bug?
Keyed, by definition, does the opposite of how solid is designed to work, and it exists anyway because it's sometimes useful
yeah that's what I'd expect honestly, because how is somebody supposed to know about this stuff, there are a lot of gotchas introduced by the transform, especially if one comes with some understanding about how JSX works already
So the fact keyed causes rerunning is pretty much by definition
The problem is that people then want to use it because they want type safety and don't want to use type assertions
It's not just the transform though, although transform is a big part
Sometimes the "simplest" thing to do (keyed Show, perfect convenient narrowing) is also the "worst" one (worst possible performance that you can get for that Show now, like not just in Solid, in general basically)
I feel like it's mentioned almost every time someone mentions keyed
But apparently without enough explanation, so as a result some people have been recommending keyed without explaining why it's bad
It's part of the problem of people answering the same questions over and over. Over time, they (me) start putting less effort into each answer
No, I didn't read the whole thread here
To be fair:
- I don't think "keyed" means anything if you don't know what it means already
- It doesn't look like the docs make this point clear, or at all as far as I can see
- Solid didn't have to make the most convenient option also the worst possible one for performance, like this use case is impossible in the code I write, because this scenario is simply not supported, because why would I make it easier to shoot myself in the foot majorly like that
Yup
Though in fairness, #3 happened because solid wasn't really written with TS in mind
The relatively excellent ts support is mostly an accident, in a sense (and major kudos to those who made it happen of course)
A bit cheeky, but it ain't called SolidJS for no reason 🤣 like you can flat-out not use magic refs without assertions I believe, you can't call render normally without a type assertion, Solid is very much not written to "comply" with TypeScript as best as possible
Whatever version of non keyed callback Show is shipped with 1.7 should be enough, no?
What's the problem?
Technically they were right I guess 🤣
Well, it didn't ship yet, and I'm not sure which version exactly is planned to be shipped
Can you please explain why this is a problem?
Oh
I thought that was the most likely contender actually
But I haven't closely followed the discussions around this
Not necessarily because as I'm understanding it @misty zinc would like the types of the functions he's (she? they?) using to be correct. And the solution Ryan seems to be leaning toward is the solution where this happens: you pass Show an Accessor<User | null>, Show gives you a function that says it's an Accessor<User>, but in reality it may return null to you in some cases. Like if part of the goal is to get no type assertions because the types by themselves are correct that's not a solution, the types are still incorrect, the type assertion just got moved inside Solid itself.
Yes
This is true, but only in cases where you synchronously set the signal value during rendering, or where accessing the signal value in a callback after cleanup (or will cleanup also be affected?)
I liked Fabio's useResolved hook, I wonder if it would be usable in JSX 🤔
I hear you though, it's definitely important
I haven't followed the discussions, so I don't know what the plans are, but I assumed that a foot gun that big would be worked around
Yes, and I think that code in particular should work well regardless of the exact option that gets chosen, but in other more convoluted edge cases the solution that gets chosen could either cause your code to throw or not (depending on the solution, mine doesn't throw, explicitly throwing obviously throws, returning null is kinda sneaky, depending on what you are doing it will actually throw, sometimes it will just produce some broken computation)
No, because the keyed version passes a value, not a signal, how would it update then?
You mean like accessors?
This is true, but only in cases where you synchronously set the signal value during rendering, or where accessing the signal value in a callback after cleanup
Correct. In other cases, which are most normal cases really, there shouldn't be a difference.
(or will cleanup also be affected?)
In what way?
Sorry I meant props
Props can be rewritten because getters on objects are a thing in javascript
It can't
There's no way to proxy a variable access in solid
It's possible, but infeasible, like I don't think anybody is capable of writing the compiler needed to get that to "just work"
But he's saying you can just make the compiler smarter, like sure you can feed your code to the gods and they will be able to make sense of it or tell you to change something, but we don't know how to write compilers that sophisticated
-
Until let decorators are added to javascript, that's impossible without turning the compiler to a compile everything instead of just jsx
-
The only thing this gains over the proposed solutions for 1.7 is the interface (passing an accessor vs value), but the trade offs considered for the different solutions are still exactly the same
Right, but I think we're in general agreement not to go down that path. Therein lies madness (and svelte and it's compiler problems)
probably closer to 1 month?
like I know as much as you do basically, but it seems close-ish
some of the messages I linked you are from Ryan and they happend like a few days ago
when did we ever write software that worked
might have been sorted by relevant
software that worked as scale is even harder to write
Classic discord
I'm not sure what this code is meant to do exactly, it you can make a working demo in the playground I'll take a look at it
this can't be just implemented with types though, which is what your code seems to do
I mean in this example is Resolved<User> equivalent to Accessor<User>? If so I guess it might be nice that this is somewhat explicit, but it seems unnecessary and a bit misleading perhaps, because your renderUser in theory could be called with just an accessor
I had ported my Show to Solid at some point actually, but good luck finding it now 🤣
