-
Notifications
You must be signed in to change notification settings - Fork 595
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
unable to use preact context in fresh #983
Comments
I think this is because context provider wouldn't be hydrated, so calling
Hope it helps. |
Hey, that's what I was thinking about, most probably due to island architecture. Implementing Cart context would be tricky in this case. |
I do have Preact Context working fine with islands. Although I'm using the equivalent of I think your primary problem is the usage of functions for parameters, which are unsupported in islands:
|
I've created a plugin to use shared context in fresh, mainly for the purpose of providing globals. It works with |
In one Stack Overflow question @marvinhagemeister says that Fresh currently doesn't support passing context values from the server to the client. I wonder why this is the case? Reading about the differences between Fresh and Preact I don't get why Fresh would lack of feature of what Preact already has. Especially on an important hook like |
@ooker777 You can use context on the server in Fresh, but you cannot use context to pass data from the server to the client. This has nothing to do with with Preact, but mainly that we didn't have time to look at how to support that in Fresh yet. Preact is just a rendering library, it has no concept of how to pass data from the server to the client. Preact has no idea of a server and that's exactly where Fresh comes in. Yes, Fresh is a wrapper around Preact and that Fresh wrapper introduces the notion of Server and a Client that Preact isn't aware of, because it's mostly just a rendering library. |
But isn't that the concept of island or partial hydration involves the interaction between server and client? How can Preact apply those concepts without having any idea about server? Where does the rendering happen? Does React have no idea of a server as well? |
Yep, islands and partial hydration involve the interaction between server and client. Thing is that those concepts are implemented in Fresh, not in Preact. Fresh calls Preact to say "render component X with props Y", but Preact has no idea where those come from, what they represent etc. That those are islands and that the props have been sent from the server to the browser is something only Fresh knows about. Fresh takes care of all of that and triggers Preact's rendering when all is done.
React has no idea of servers. It's the meta-frameworks around it like Next.js, Remix and other's that introduce the concept of a server and a client and the glue to make them work together. This distinction is true for other frontend frameworks as well. The frameworks themselves mostly provide only a rendering layer and the meta-frameworks around it provide the rest.
Routing and all the other typical needs of an app are provided by the right column, not the left. The original frameworks in the left column only deal with rendering and reacting to state updates. |
There are use cases that is almost impossible to separate cleanly between server and client. Imagine a use case of an interactive form with i18n where sections in the form are conditionally rendered via Signals, while text, labels, placeholders have to be translated in a server context. Here is a simple example for brevity: <input
placeholder={useTranslation("Type here")} // Requires server (context)
onChange={() => { isDirty.value = true; }} // Requires client (island)
/> The issue comes in two flavors,
Are there recommended ways to design an app structure around these issues? EDIT: Some afterthoughts Fresh seems to chop off at the first island and the whole subtree is passed to the client side. This example of i18n means the context value can be too large to pass down the client, hence the rendering of descendents below the first island is still best done server side. True server components must be rendered at server side even if they are the children of an island, the whole tree is then pieced back together at client side. |
I created https://github.com/deer/fresh/tree/983_reproduction/tests/fixture_component_in_island to reproduce this situation. I have an index page which has an island, and the island has a component. So the server sends out: <div id="index">
Hello from the index. IS_BROWSER: false
<!--frsh-island_default:0:-->
<div id="island">
Hello from an island. IS_BROWSER: false
<div id="component">Hello from a component. IS_BROWSER: false</div>
</div>
<!--/frsh-island_default:0:-->
</div> But what ends up getting rendered is: <div id="index">
Hello from the index. IS_BROWSER: false
<div id="island">
Hello from an island. IS_BROWSER: true
<div id="component">Hello from a component. IS_BROWSER: true</div>
</div>
</div> @vicary, what you want is the following, right? <div id="index">
Hello from the index. IS_BROWSER: false
<div id="island">
Hello from an island. IS_BROWSER: true
<div id="component">Hello from a component. IS_BROWSER: false</div>
</div>
</div> So whatever's rendered on the server for my poorly named To save some time, I'll include the three (boring) implementations here: routes/index.tsximport { IS_BROWSER } from "$fresh/runtime.ts";
import Island from "../islands/Island.tsx";
export default function Home() {
console.log("index: " + IS_BROWSER);
return (
<div id="index">
Hello from the index. IS_BROWSER: {IS_BROWSER === true ? "true" : "false"}
<Island />
</div>
);
} islands/Island.tsximport { IS_BROWSER } from "$fresh/runtime.ts";
import Component from "../components/Component.tsx";
export default function Island() {
console.log("island: " + IS_BROWSER);
return (
<div id="island">
Hello from an island. IS_BROWSER: {IS_BROWSER === true ? "true" : "false"}
<Component />
</div>
);
} components/Component.tsximport { IS_BROWSER } from "$fresh/runtime.ts";
export default function Component() {
console.log("component: " + IS_BROWSER);
return (
<div id="component">
Hello from a component. IS_BROWSER: {IS_BROWSER === true ? "true" : "false"}
</div>
);
} |
@deer Yes. And to leave no room for interpretation, I would add two changes to emphasize the transparency before and after the first island in the DOM tree.
|
I managed to use preact
createContext
hook as the following:hooks/ShoppingCartProvider.tsx
and then tried to import it in an island like this
also encapsulate the _app.tsx with the provider
and then run
deno start task
I am getting the following errorwhich refers to this particular line
L2(ShoppingCartContext).getCart()
Is it something expect? I tried the same scenario with nextjs and it is working as expected with context accessible everywhere.
Thanks in advance 😃
The text was updated successfully, but these errors were encountered: