#why does this playground link re-render the outer component?

133 messages · Page 1 of 1 (latest)

edgy onyx
#

"keyed" opts you into that behavior, if you delete "keyed" it will not re-render the entire thing

#

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

paper bramble
#

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

edgy onyx
#

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 number and 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?

edgy onyx
#

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

#

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 🤣

paper bramble
#

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

edgy onyx
#

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

paper bramble
#

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

edgy onyx
#

yes, the same code compiled with just typescript, or with typescript + solid, is completely different some times

paper bramble
#

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

edgy onyx
#

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

paper bramble
#

If you're writing functions the way you are (they take arguments, not props), you absolutely should pass signals to the functions, not values

edgy onyx
#

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

paper bramble
#

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

paper bramble
edgy onyx
#

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

paper bramble
#

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

paper bramble
edgy onyx
#

mind blowing

paper bramble
#

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

edgy onyx
paper bramble
#

The problem is that people then want to use it because they want type safety and don't want to use type assertions

paper bramble
edgy onyx
#

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)

paper bramble
#

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

edgy onyx
# paper bramble Keyed, by definition, does the opposite of how solid is designed to work, and it...

To be fair:

  1. I don't think "keyed" means anything if you don't know what it means already
  2. It doesn't look like the docs make this point clear, or at all as far as I can see
  3. 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
paper bramble
#

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)

edgy onyx
#

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

paper bramble
#

Whatever version of non keyed callback Show is shipped with 1.7 should be enough, no?

#

What's the problem?

edgy onyx
#

Technically they were right I guess 🤣

paper bramble
#

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

edgy onyx
# paper bramble Whatever version of non keyed callback Show is shipped with 1.7 should be enough...

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.

paper bramble
#

Yes

paper bramble
signal ether
#

I liked Fabio's useResolved hook, I wonder if it would be usable in JSX 🤔

paper bramble
#

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

edgy onyx
#

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)

paper bramble
#

No, because the keyed version passes a value, not a signal, how would it update then?

#

You mean like accessors?

edgy onyx
paper bramble
#

Sorry I meant props

#

Props can be rewritten because getters on objects are a thing in javascript

paper bramble
#

There's no way to proxy a variable access in solid

edgy onyx
#

It's possible, but infeasible, like I don't think anybody is capable of writing the compiler needed to get that to "just work"

edgy onyx
paper bramble
#
  1. Until let decorators are added to javascript, that's impossible without turning the compiler to a compile everything instead of just jsx

  2. 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

paper bramble
edgy onyx
#

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

signal ether
#

might have been sorted by relevant

edgy onyx
#

software that worked as scale is even harder to write

signal ether
#

Yeah, then I guess it had to re-index

#

I usually just search for fabio's messages

signal ether
#

Classic discord

edgy onyx
#

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

signal ether
#

I think someone did something similar to this

#

#typescript message

edgy onyx
#

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

edgy onyx