ryancharris / use-fauna

React hooks for interacting with Fauna databases
https://fauna.com/
43 stars 3 forks source link

[Discussion] Provide configuration through Context API #26

Open ecwyne opened 4 years ago

ecwyne commented 4 years ago

Instead of providing a Client instance to each hook, it would be much cleaner and more intuitive to provide client parameters through context.

Prior art: vercel/swr @apollo/client tannerlinsley/react-query

ryancharris commented 4 years ago

@ecwyne Thanks for the note 👍 I've actually been thinking about that as well. When I refactored useDatabase to be useFaunaClient I was considering changing the former to provide some Context values to use throughout the app. I'll certainly take a look at the references you provided me.

My think is if we instantiate a Client with useFaunaClient we can pipe it to the sub-tree with a Context provider for components that care. This way, we could also use different clients for different parts of the app if we don't want all the data living in one DB.

What do you think?

ecwyne commented 4 years ago

I definitely think it's possible to make it so that you can pass different client parameters to different sub-trees and merge them with the configurations from parent providers.

Eg.

<FaunaProvider config={{ secret: 'secret1' }}>
    <ComponentOne />
    <FaunaProvider config={{ secret: 'secret2' }}>
        <ComponentTwo />
    </FaunaProvider>
    <FaunaProvider  config={{ observer: console.log }}>
        <ComponentThree />
    </FaunaProvider>
</FaunaProvider>
ecwyne commented 4 years ago

I would suggest having a useFaunaClient hook that uses the configuration options provided in context to create the Client instance. It would not be possible to merge configurations if you're passing down the Client instance itself

const useFaunaClient = () => {
    const { config } = useContext(FaunaContext);
    return new Client(config);
};
ryancharris commented 4 years ago

I definitely think it's possible to make it so that you can pass different client parameters to different sub-trees and merge them with the configurations from parent providers.

Eg.

<FaunaProvider config={{ secret: 'secret1' }}>
    <ComponentOne />
    <FaunaProvider config={{ secret: 'secret2' }}>
        <ComponentTwo />
    </FaunaProvider>
    <FaunaProvider  config={{ observer: console.log }}>
        <ComponentThree />
    </FaunaProvider>
</FaunaProvider>

Awesome. I was definitely thinking something along these lines 🙌 I can imagine folks wanting to isolate data from different parts of their app in different DBs, which they can provide to pages/components through a Context.Provider.

ryancharris commented 4 years ago

I would suggest having a useFaunaClient hook that uses the configuration options provided in context to create the Client instance. It would not be possible to merge configurations if you're passing down the Client instance itself

const useFaunaClient = () => {
    const { config } = useContext(FaunaContext);
    return new Client(config);
};

Originally, I was thinking useFaunaClient would work as it does now and that you'd then pass it into a useDatabase hook. That hook would return a Context and a Context provider with the Client instance as its value.

Something like this:

// App.js
const client = useFaunaClient(KEY)
const [DatabaseProvider] = useDatabase(client)

return (
  <DatabaseProvider>
    <Component1 />
    <Component2 />
  </DatabaseProvider>
)

// Component2
const client = useFaunaClient(KEY)
const [DataContext] = useDatabase(client)
const data = useContext(DataContext)

What do you think? Certainly not married to this implementation 😅

ecwyne commented 4 years ago

As written useFaunaClient requires you to keep track of a secret throughout your app and pass it every time.

I believe useFaunaClient shouldn't take any arguments at all and returns a client based on the context it's being run in. This is how useApolloClient works

Also, I'm not sure what you mean by Database. (In your example useDatabase() returns either a [DatabaseProvider] or [DataContext]?

In practice, I almost never think about the Fauna idea of a Database. I use a client to read Documents from Collections, match Indexes, and call Functions.