denoland / fresh

The next-gen web framework.
https://fresh.deno.dev
MIT License
12.17k stars 621 forks source link

docs: explain better the distinction between islands and components #2369

Closed skybrian closed 4 months ago

skybrian commented 5 months ago

Quoting @CAYdenberg in: https://github.com/denoland/fresh/issues/2363#issuecomment-2004817651

Well, if it helps, components that are children of islands can receive functions as props. So, your ComplexOrBigComponent could live in components/, receive onClick when used as a descendent of an island, and not receive it when used outside of an island. Just mark onClick as being optional in your props interface declaration (and handle the cases where it is undefined).

I also found this confusing at first. When should a file go under components/ versus islands/?

I had thought that islands were client-side and components were server-side, but that's not right. Instead, everything should be a component, except when it needs to be the root of a client-side hierarchy, and then it's an island. (Why? Because there are restrictions on what you can pass in to an island.)

In particular, the component page has some components tagged as islands that are really just components that can run on both client and the server. (A button could be an island, but why?)

fro-profesional commented 5 months ago

I don think is confusing, from the docs: https://fresh.deno.dev/docs/concepts/islands

Islands enable client side interactivity in Fresh. Islands are isolated Preact components that are rendered on the server and then hydrated on the client. This is different from all other components in Fresh, as they are usually rendered on the server only.

You mentioned

In particular, the component page has some components tagged as islands that are really just components that can run on both client and the server.

Thats what islands are, thats what the docs says "components that are rendered on the server and then hydrated on the client."

And for

(A button could be an island, but why?)

Why would not? buttons can be used to trigger forms by using props, or actions by onClick event, for the second will always be necessary to be an island or be used inside and island

CAYdenberg commented 5 months ago

I think based on the fact that multiple people are confused (who presumably took the time to try to understand, since they took the time to give feedback), that by definition it is confusing.

I think the concept that needs to be fleshed out is that the children of islands are still "within" the island. Or, put differently, a distinction should be made between the island "entry-point" and the components which are part of the island.

However, I am not a maintainer, so I won't make the call myself. It's also possible the change should be folded into the broader re-org of the Getting Started section (#1632 )

fro-profesional commented 5 months ago

I think based on the fact that multiple people are confused (who presumably took the time to try to understand, since they took the time to give feedback), that by definition it is confusing.

I guess u are right 🤔

marvinhagemeister commented 5 months ago

Component

A function that starts with an uppercase letter that can use hooks and optionally return JSX. Doesn't say anything about where it runs.

Island

A form of component that is bundled and executed it in the browser, looks the exact same as a normal component. The only difference is that they're put in special files like islands/MyIsland.tsx and Fresh flags components exported from these as an island.

Server Component

A form of component that's only run on the server. Looks the exact same as a normal component, only difference is where it's used. For Fresh means that if you only ever use this component in a route, then it will only run on the server.

kerimhudson commented 4 months ago

Just as an anecdote, I did find this somewhat confusing at first, especially because I copied the Button island into a component in my Fresh project, and then was confused why it was constantly disabled. Of course, now this makes sense to me.

But then when I look at the interactive islands documentation now, looking at the following example:

islands/my-island.tsx
import { useSignal } from "@preact/signals";

export default function MyIsland() {
  const count = useSignal(0);

  return (
    <div>
      Counter is at {count}.{" "}
      <button onClick={() => (count.value += 1)}>+</button>
    </div>
  );
}

It's now clear to me that the button here, could be a components/Button and still function perfectly fine. I wonder if in a documentation level it's worth just creating an example which illustrates this use case a little more? Something like:

islands/my-island.tsx
import { useSignal } from "@preact/signals";
import Button from '../components/Button.tsx'

export default function MyIsland() {
  const count = useSignal(0);

  return (
    <div>
      Counter is at {count}.{" "}
      <Button onClick={() => (count.value += 1)}>+</Button>
    </div>
  );
}