Skip to content
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

useContext inside a handler. #1339

Open
osvald0 opened this issue Jun 21, 2023 · 16 comments · May be fixed by #1375
Open

useContext inside a handler. #1339

osvald0 opened this issue Jun 21, 2023 · 16 comments · May be fixed by #1375

Comments

@osvald0
Copy link

osvald0 commented Jun 21, 2023

Is it posible to use useContext inside a handler?

@marvinhagemeister
Copy link
Collaborator

Which kind of handler do you mean? Can you share more information about where you want to use the useContext hook?

@osvald0
Copy link
Author

osvald0 commented Jun 21, 2023

Yes, sure. sorry for the missing information:

Something like this:

export const handler: Handlers = {
  async POST(req, ctx) {
    const { login } = useAuth();
    const mycontext = useContext(MyContext); // Context inside handler here.

    const form = await req.formData();
    const email = form.get("email")?.toString() || "";
    const password = form.get("password")?.toString() || "";

    const response = await login({ email, password });

    if (response) {
      // Do something with mycontext here!

      const url = new URL(req.url);
      url.pathname = "/";
      return Response.redirect(url);
    }
    return await ctx.render(response);
  },
};

export default function Login({ data }: PageProps<AuthResponse>) {
  return (
    <MyFormHere/>
  )
}
@marvinhagemeister
Copy link
Collaborator

I see, thanks for providing further information. It looks like you want to be able to access from a request middleware. Where would you expect the context to be set?

The current flow is:

  1. Browser sends request
  2. Request middlewares are executed (if any)
  3. If it was a GET request -> render route.
@osvald0
Copy link
Author

osvald0 commented Jun 22, 2023

My idea (I'm not sure if it's ok or not) is to assign to the context the user information from the success login in the handler.

@deer
Copy link
Contributor

deer commented Jun 26, 2023

But isn't that what https://fresh.deno.dev/docs/concepts/data-fetching is all about? Do something asynchronous in the handler, and then (optionally) pass that information to the render function.

If you want to receive information from a previous middleware, then look into State which is briefly discussed here https://fresh.deno.dev/docs/concepts/middleware. In particular, each middleware has a ctx, and ctx.state can be mutated. The mutated value gets passed along the chain of middleware handlers.

If you really need some heavy duty initialization (the kind of thing that should only get done once, during server startup) then look at https://fresh.deno.dev/docs/examples/init-the-server.

Do these help to clarify? If not, please provide more details.

@CAYdenberg
Copy link
Contributor

@osvald0 When you say useContext are you asking about the (p)react hook?

@osvald0
Copy link
Author

osvald0 commented Jun 27, 2023

@CAYdenberg Yes.

@deer I finally replaced the context by a signal variable without the context. I know how the handler works, the idea behind the context was to to put some information available there (context) without need to fetch again the same thing later in other handler.

@CAYdenberg
Copy link
Contributor

The handler itself is not a component and is outside the preact scope, so you can't use hooks.

@deer
Copy link
Contributor

deer commented Jun 29, 2023

Is there anything else to do here? I'm still a bit confused about your use case. You want to store something in (p)react context in a handler (which isn't possible) so that it can be used by another handler. But there's only one handler per request, so it sounds like you want something which can persist data across transactions. This seems like a case for Deno KV or some other database. (Of course, there can be multiple middleware handlers per request, which is why there is State.) Have I misunderstood something?

Additionally, I created the following small demo to clarify things. This isn't what you're doing (I think?):
/routes/index.tsx

import { HandlerContext, PageProps } from "$fresh/server.ts";
import { createContext } from "preact";
import { Child } from "../components/Child.tsx";

export const ComplexContext = createContext("");

export const handler = async (
  _req: Request,
  ctx: HandlerContext,
): Promise<Response> => {
  const complexValue = "this is complex";
  return await ctx.render(complexValue);
};

export default function Home(props: PageProps<string>) {
  return (
    <ComplexContext.Provider value={props.data}>
      <Child />
    </ComplexContext.Provider>
  );
}

/components/Child.tsx

import { Grandchild } from "./Grandchild.tsx";

export function Child() {
  return <Grandchild />;
}

/components/Grandchild.tsx

import { ComplexContext } from "../routes/index.tsx";
import { useContext } from "preact/hooks";

export function Grandchild() {
  const value = useContext(ComplexContext);
  return <div>{value}</div>;
}

@marvinhagemeister, should I document this pattern? Something like "Using useContext to avoid prop drilling"

@osvald0, please provide some runnable code to clarify your case. This could be something we want to add to the docs.

@marvinhagemeister
Copy link
Collaborator

@deer Might be useful to document, but I'm not sure if context at the root that's subscribed inside islands works at the moment.

@deer
Copy link
Contributor

deer commented Jun 29, 2023

This is code from a live demo that does what's expected. I.e. when I hit http://localhost:8000/ I receive a page that has this is complex as the body.

I'll create a PR to document this pattern. If osvald0 responds, I can document his pattern as well, if necessary.

@deer
Copy link
Contributor

deer commented Jun 29, 2023

Oh, I see, you're mentioning islands. Totally right, that doesn't work yet.

@deer deer linked a pull request Jun 30, 2023 that will close this issue
@osvald0
Copy link
Author

osvald0 commented Jun 30, 2023

The handler itself is not a component and is outside the preact scope, so you can't use hooks.

Hello! Sorry for the late response. Here and example where you can see custom hooks works fine in a handler. What are the hooks not working inside a handler?

@CAYdenberg
Copy link
Contributor

you can see custom hooks works fine in a handler

That isn't really a hook, it's just a function that happens to start with the prefix "use". If it called useState or useContext within it, it would need access to the preact runtime and it would break.

See https://legacy.reactjs.org/docs/hooks-rules.html for an explanation.

@osvald0
Copy link
Author

osvald0 commented Jun 30, 2023

Yes, hooks are javascript functions by definition :)

Screenshot 2023-06-30 at 19 00 06

I updated my example and I can confirm your Context example works fine.

@osvald0
Copy link
Author

osvald0 commented Jun 30, 2023

Now I know what I was trying to do is not supported but here you have an example to understand was the idea the idea.

Thanks guys!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
4 participants