logto-io / js

🤓 Logto JS SDKs.
https://docs.logto.io/quick-starts/
MIT License
67 stars 40 forks source link

LogToProvider Optionally Accept LogToClient Instance Instead Of Config #608

Closed jhchill666 closed 5 months ago

jhchill666 commented 10 months ago

What problem did you meet?

Whilst building a traditional React app, the useLogTo hook is sufficient for accessing the methods on the LogToClient instance, via the LogToProvider.

But when needing to access this instance outside of the React component tree, we have to jump through hoops/roll-our-own, to make it available to us.

If we were able to provide a client instance to the provider, we could use this elsewhere without much effort.

Create client

// client.ts

import LogtoClient from '@logto/browser'

import { logToConfig } from './config'

export const logtoClient = new LogtoClient(logToConfig)

Add client to provider

// App.tsx

import { logToClient } from "./client"

const App = () => (
  <LogtoProvider client={logtoClient}>
    <Routes />
  </LogtoProvider>
)

Use client elsewhere outside of react component tree

// apolloLinks.ts

import { setContext } from '@apollo/client/link/context'
import { logToClient } from "./client"

export const authLink = () =>
  setContext(async (_, { headers }) => {
    const accessToken = await logtoClient.getAccessToken()
    return {
      headers: {
        Authorization: `Bearer ${accessToken}`,
      },
    }
  })
charIeszhao commented 10 months ago

Hi, can you please elaborate on what is missing from the useLogto hook, or in orther words, what else do you want from the LogtoClient instance?

Also, what do you mean by traditional React app? Is that a server-side rendering project using React component, like... Next.js? Is this @apollo something like that?

charIeszhao commented 10 months ago

Ah, I see... It seems you just want to use getAccessToken in a util method outside of the component tree, right? If this is the case, then usually we recommend to create a hook instead, since React hooks can be used in both components and hooks.

So is it possible to refactor your apolloLinks.ts to a React hook? Then you'll be able to call useLogto in it

jhchill666 commented 10 months ago

By traditional React app I meant "not NextJS or anything else".

My use case specifically pertains to providing the accessToken to my Apollo Client instance. I need to make authenticated GraphQL requests. The code for instantiation of Apollo has nothing to do with React, and therefore hooks are not an option.

I simply need access to the initial LogToClient instance, which hooks do not allow for. As per my example, passing a client instance that I've instantiated to the Provider, would allow me to invoke methods on that instance, outside of React.

See this example of how Apollo Client does exactly that. Is a fairly common pattern.

charIeszhao commented 10 months ago

I see apollo also support React hooks, since it even provides useQuery hook out-of-the-box. I see no blocker of wrapping your authentication logic inside a hook.

We have similar logic in our Logto console, that we need to set the authentication header when making requests. The code is wrapped in a useApi hook, and it should be the same case for you IMHO. Source code: https://github.com/logto-io/logto/blob/master/packages/console/src/hooks/use-api.ts#L108-L111

jhchill666 commented 10 months ago

I think you're missing the point somewhat.

Hooks are only available inside the React render tree. I need to access the client outside of the React render tree. See LogTo NextJS example, here, inside a NextJS api route. You're importing the client. This is outside the render tree, has nothing to do with react.

charIeszhao commented 10 months ago

Hooks are only available inside the React render tree. I need to access the client outside of the React render tree.

I would like to know where you would use the apolloAuth.ts. At the end of a day, all the utils and methods that you declared outside of the React render tree are all going to be imported by a page inside the React render tree, right? At least this is true in a React app.

Also in your main post, you said it would be better if we were able to put LogtoClient instance in the LogtoProvider, which confuses me. Isn't the LogtoProvider still inside the React render tree?

I may be wrong, though. So do you have a sample project that can help me better understand your code structure?

wangsijie commented 5 months ago

Closing this issue for now. If you encounter further problems, feel free to reopen it.