invertase / tanstack-query-firebase

React Query hooks for managing asynchronous operations with Firebase. Supports Authentication, Analytics, Firestore & Realtime Database.
https://react-query-firebase.invertase.dev
Apache License 2.0
395 stars 70 forks source link

How do I pass variables to hooks? #80

Open charlestbell opened 2 years ago

charlestbell commented 2 years ago

When I've used React Query before, I used it as a hook. Like Tanner showed in this demo: https://youtu.be/DocXo3gqGdI?t=2817

And also in the React Query Docs, https://tanstack.com/query/v4/docs/guides/mutations It shows how data can be passed into a useMutation that runs inside mutationFn. This allows you to abstract a 'useUpdateMyData' hook, or something like that. And it has all of the fetching logic inside, and you just pass a small amount of data to make it mutate different documents.

function App() {
  const mutation = useMutation({
    mutationFn: newTodo => { // Right here, data comes in as newTodo
      return axios.post('/todos', newTodo)
    }
  })

  return (
    <div>
      {mutation.isLoading ? (
        'Adding todo...'
      ) : (
        <>
          {mutation.isError ? (
            <div>An error occurred: {mutation.error.message}</div>
          ) : null}

          {mutation.isSuccess ? <div>Todo added!</div> : null}

          <button
            onClick={() => {
              mutation.mutate({ id: new Date(), title: 'Do Laundry' })
            }}
          >
            Create Todo
          </button>
        </>
      )}
    </div>
  )
}

I incorporated that into custom hooks on other projects:

import 'react-native-get-random-values';
import Constants from 'expo-constants';
import { useMutation, useQueryClient } from 'react-query';
import getDbName from '../../utils/loadDatabaseName';
const CosmosClient = require('@azure/cosmos').CosmosClient;

const containerId = 'logbooks';

export const useDeleteLogbook = () => {
  const queryClient = useQueryClient();
  const { mutate: deleteLogbook } = useMutation(
    newLogbook => mutation(newLogbook),
    {
      onSuccess: () => {
        queryClient.invalidateQueries('logbooks');
      },
    }
  );
  return { deleteLogbook };
};

const mutation = async logbook => { // Right here, my dynamic data comes into my hook as 'logbook'
  const endpoint = await Constants.manifest.extra.cosmosEndpoint;
  const key = await Constants.manifest.extra.cosmosKey;
  const databaseId = await getDbName();
  const client = new CosmosClient({ endpoint, key });

  await client
    .database(databaseId)
    .container(containerId)
    .item(logbook.id, logbook.userId)
    .delete();
};

Then in my code, I could use the hook and it was incredibly clean:


// Inside react component:
const { deleteLogbook } = useDeleteLogbook();
          onPress: () => deleteLogbook(logbook),

But now I'm trying to do the same thing with this package, and I'm running into trouble.

I've implemented a custom deletion hook like so. But I can't find a way to pass dynamic variables in as before.

import { collection, doc } from 'firebase/firestore';
import { useFirestoreDocumentDeletion } from '@react-query-firebase/firestore';
import { db } from '../../utils/firebase';

export const useDeleteLogbook = () => {
  const collection = collection(db, 'logbooks');
  const ref = doc(collection, '456');// I want to pass a dynamic value here instead of 456
  const { mutation: deleteLogbook } = useFirestoreDocumentDeletion(ref);
  return { deleteLogbook };
};

According to your example, you call the mutate function with no data passed in. Just mutation.mutate()

 <button
        disabled={mutation.isLoading}
        onClick={() => {
          mutation.mutate(); // No data passed in
        }}
      >
        Delete document
      </button>

https://react-query-firebase.invertase.dev/firestore/data-mutation

So I'm wondering, how do we implement this with dynamic data? For example, if I have a list, where each item has a delete button. How do I pass in mutation.mutate(<clickedElement'sId>) so that my react-query-firebase code can delete the correct document?

Could you point me in the right direction or give me a small example?

I tried reading the code of this package, but I'm not great with typescript yet.

alexco4532 commented 2 years ago

How about something like this?

https://pastebin.com/BH7fcit9

charlestbell commented 2 years ago

Thanks for the reply @alexco4532.

What you have there is basically what's in the docs.

To make that work, I'd have to put the useDeleteLogbooks hook into button component, and then have that button component be duplicated a whole bunch of times in say, a list of logbooks. It's not the end of the world, but it's also not how my app is built currently and I don't care for it.

In the end I decided to drop this package because it wouldn't refresh the data, even if your specified source: "server" and forced a refresh.

Thanks again for taking the time!