Git Product home page Git Product logo

Comments (13)

mcandeia avatar mcandeia commented on July 17, 2024 1

React Server Component is going towards an approach like the async componente proposition. Maybe, we can be smart in the engine and make an async component like signature work without needing the extra closure. This would be nice since we would be future proof. I'd like to write something on the lines:

async function Section() {
  const response = await fetch()
  
  return <div>{response.data}</div>;
}

I agree. But I tried it using a few different ways without success. Looks like that I can't invoke the function with params and use the response directly due to the lack of fresh hooks that should be attached before the rendering. Invoking the function will make fresh have no chance to jump and do its magic,

So @igorbrasileiro and @tlgimenes, I'll be very happy if you guys can go ahead help me on achieve this on the next steps.

My proposal is: Since this is a technical limitation for now, I'd rather prefer to be pragmatic and select between the real possibilities.

Notice that changing from the current proposal to the one that you mentioned is not a breaking change, thus can be a step moving forward as soon as we realize how to make this work.


I'd like to share some thoughts that isn't obvious when moving from async components proposal that does not make it worse, but makes both proposal very similar in terms of advantages and disavantages:

  1. When separating data-fetching from components we make refactoring code easier. Sections are just sections and loaders are just loaders, they're not coupled together, meaning that the component and the loader can be reused separately. (imported from another section). Notice that an async section will also be a "deco-only" concept. Assuming that the section won't be reusable across code
  2. Islands and sections can be isomorphic, we can also provide a inline loader for islands that happen on server-side in the same way we do for sections. However, making islands async is a no-go, not only speaking in terms of limitations but also in terms of composability, islands is a fresh concept and we can cause confusion when trying to make them async.

from deco.

mcandeia avatar mcandeia commented on July 17, 2024

WIP PR: #153

from deco.

lucis avatar lucis commented on July 17, 2024

I really like the simplicity of it!

Inline loaders are awesome

from deco.

guifromrio avatar guifromrio commented on July 17, 2024

This an amazing step.

I have one nit: I think we need to make it simpler to understand that I can "substitute" one of the props of my section for an async inline loader (instead of receiving through props or receiving through an external loader).

What I mean is: it's not trivially clear that LoaderProps will pass through and some of it will "fall down" to Props.

When I think about it, it seems to me that the easy way to explain it is something like:

  • You can have a static component - no props
  • You can have a component that receives static props - configure them on admin
  • You can have a component that loads part of the props with I/O - is this the level we're discussing?
  • And finally, you can have a component that loads part of the props with I/O and you can configure how that loads independently in the admin and reference it. (Is this where we started with loaders?)

Am I making any sense? :)

import { PropsLoader } from "$live/mod.ts";
import type { LoaderContext } from "$live/types.ts";

export interface Props {
  title: string;
  dogFacts: string[];
}

export default function DogFacts({ title, dogFacts }: Props) {
  return (
    <div class="p-4">
      <h1 class="font-bold">{title}</h1>
      <ul>
        {dogFacts.map((fact) => <li>{fact}</li>)}
      </ul>
    </div>
  );
}

export const loader: PropsLoader<Props> = {
  dogFacts: async function(_req: Request, { state: { $live: { numberOfFacts } } }: LoaderContext<LoadProps>,): Promise<string[]> {
    const { facts } = (await fetch(
      `https://dogapi.dog/api/facts?number=${numberOfFacts ?? 1}`,
    ).then((r) => r.json())) as { facts: string[] };
    return facts;
  },
};

Perhaps my question is: if you're an inline loader, why would you need a different set of properties? you're inline. You are just a part of a section. When you start requiring properties that make sense for you but not for your section, bingo: you have arrived at the need to extract a loader.

How does that sound?

from deco.

mcandeia avatar mcandeia commented on July 17, 2024

Thanks for the feedback @guifromrio,

What I mean is: it's not trivially clear that LoaderProps will pass through and some of it will "fall down" to Props.

I agree but just to make it clear: It should be typesafe. The props loader will tell the developer which properties are "required" (e.g)

If title is optional in LoaderProps but required in SectionProps so the propsLoader MUST return a title regardless (in this case might be use a default value in case of not provided)

LoaderProps SectionProps Optional?
Optional Optional Yes
Optional Required No
Required Optional Yes
Required Required Yes
Missing Prop Optional Yes
Missing Prop Required No

Perhaps my question is: if you're an inline loader, why would you need a different set of properties? you're inline. You are just a part of a section. When you start requiring properties that make sense for you but not for your section, bingo: you have arrived at the need to extract a loader.

How does that sound?

If I understood your points correctly, you're saying that the loader should receive the same set of properties as the section, right? If so, in your example where the numberOfFacts comes from? (LoaderProps)

Isn't this a new property that should makes the dev extract the loader ?

Correct me If I'm wrong, and thanks again for the detailed feedback!

from deco.

guifromrio avatar guifromrio commented on July 17, 2024

Yes, I think that if you are uncomfortable having numberOfFacts as part of your Section Props API, then you are saying that this is not the correct abstraction layer for that information — therefore, go and extract a Type and implement an external TypeLoader. That can receive it's own props, have it's own block lifecycle, be referenced, etc. WDYT?

from deco.

mcandeia avatar mcandeia commented on July 17, 2024

Understood, need to ask others opinion's, @lucis ?

Personally, I'm afraid the developers will add "unused" properties on purpose just to be able to use the inline loader, you know? An alternative would be generating the following:

type AdminForm = SectionProps | LoaderProps.

If SectionProps is fulfilled so it will be used instead (or the loader can do products: props.products ?? await fetchProducts()), but not sure if this will cause confusion either

from deco.

mcandeia avatar mcandeia commented on July 17, 2024

So the way I see is the following:

  1. You can have a static component - no props
  2. You can have a component that receives props - configure them on admin (either coming from loaders or from inline data, I prefer to not separate async - not async, it does not matter from the section's point of view e.g we can have "fromUrl/fromState" loader which is not async)
  3. You can have a component that depends on external data and then write an inline loader - thus be aware that you cannot swap out the fetching part

In other words: I think the dev should not worry about fetching data when creating a Universal Component - a component that just receives props and makes no IO (or it can but configurable). There are devs that will build components to be used across repositories (reusable blocks) there are devs that will create components to be used in multiple places but within the same repo - this is the perfect usecase of inline data fetching

Notice that you can still depends on product[] and leveraging inline loader (which means that a component can be Universal but "impure" ?)

from deco.

tlgimenes avatar tlgimenes commented on July 17, 2024

React Server Component is going towards an approach like the async componente proposition. Maybe, we can be smart in the engine and make an async component like signature work without needing the extra closure. This would be nice since we would be future proof. I'd like to write something on the lines:

async function Section() {
  const response = await fetch()
  
  return <div>{response.data}</div>;
}

from deco.

igorbrasileiro avatar igorbrasileiro commented on July 17, 2024
async function Section() {
  const response = await fetch()
  
  return <div>{response.data}</div>;
}

IMO, this approach seems reasonable because the framework only has one way to express props to the admin form. The Fetch inside component is just a "fetch" and not a "inline loader".

from deco.

guitavano avatar guitavano commented on July 17, 2024

I don't know how to contribute technically, but if help you in a decision. I like idea to fetch data inside a section without loaders.

Loaders are powerful, but I think we need to give the opportunity to do amazing things without them. At Hackathon, that was a rock in the learning courve of new devs.

I like the first code structure showed in this proposal, reminds me the "getServerSideProps" of next.js and looks like easy to use.

from deco.

mcandeia avatar mcandeia commented on July 17, 2024

Great @guitavano, this proposal is already merged and ready to be used! Thanks for your contribution!

from deco.

mcandeia avatar mcandeia commented on July 17, 2024

Available since 1.0.0-rc.53

from deco.

Related Issues (17)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.