0

I want to add the total number of clicks using the increment field value but when I try to open the link I created, the total clicks do not increase at all.

did I do something wrong?

import {useParams} from 'react-router-dom';
import { useEffect, useState } from 'react';
import React from 'react';
import { firestore, app } from '../../firebase';
import { CircularProgress, Box, Typography } from '@mui/material';

function LinkRedirect() {
  const {shortCode} = useParams();
  const [loading, setLoading] = useState(true)

  useEffect(() => {
      const fethLinkDoc = async () => {
        const linkDoc = await firestore.collection('links').doc(shortCode).get();
        if (linkDoc.exists){
           const{ longURL, linkID, userUid} = linkDoc.data();
           firestore.collection('users').doc(userUid).collection('links').doc(linkID).update({
            totalClicks: app.firestore.FieldValue.increment(1)
           })
           window.location.href = longURL;
        } else {
          setLoading(false)
        }
      }
      fethLinkDoc()
  }, [])
  
  if (loading) 
  return ( 
  <Box mt={10} textAlign="center">
    <CircularProgress />
    <Typography>Redirecting to the link</Typography>
  </Box>
  )
  else return (
    <Box mt={10} textAlign="center">
      <Typography>Link is not valid</Typography>
    </Box>
  )
}

export default LinkRedirect
Lavigne
  • 3
  • 2

1 Answers1

1

The problem is caused by these lines:

firestore.collection('users').doc(userUid).collection('links').doc(linkID).update({
  totalClicks: app.firestore.FieldValue.increment(1)
})
window.location.href = longURL;

Here you queue the document update operation to increment the counter, then immediately navigate away from the page, cancelling the operation.

Because you are using an async function, you can simply add await before the call to update():

await firestore.collection('users').doc(userUid).collection('links').doc(linkID).update({
  totalClicks: app.firestore.FieldValue.increment(1)
})
window.location.href = longURL;

However, I'd refactor your fethLinkDoc method to the following for readability:

const fethLinkDoc = async () => {
  const linkDoc = await firestore.collection('links').doc(shortCode).get();
  if (!linkDoc.exists) { // fail-fast
    setLoading(false)
    return
  }
  
  const { longURL, linkID, userUid } = linkDoc.data();
  
  await firestore.collection('users')
    .doc(userUid)
    .collection('links')
    .doc(linkID)
    .update({
       totalClicks: app.firestore.FieldValue.increment(1)
    })
  
  window.location.href = longURL;
}

Note: Your code currently doesn't properly handle when any of the firebase operations reject their promises. Either handle it manually or make use of an utility method like useAsyncEffect from a library.

samthecodingman
  • 23,122
  • 4
  • 30
  • 54
  • but now when I open the link, in firestore the total number of clicks immediately increases by 2 instead of 1 and when "redirecting" I can see the signin page before it is fully redirected. – Lavigne Jan 05 '23 at 03:51
  • @Lavigne That sounds like you've got a state management problem on your hands. Your component is attached, it fires an increment, the component is detached (e.g. when showing your sign in prompt), your component is attached again (after realising the user is already signed in), and it fires another increment before finally redirecting. Your code doesn't cancel when the component is detached - which is something that can be handled by using `useAsyncEffect`. But first, fix up your sign in state logic. – samthecodingman Jan 05 '23 at 04:00
  • @Lavigne Have a read of this [answer](https://stackoverflow.com/a/71182019/3068190) and the ones linked to it. This [thread](https://stackoverflow.com/q/68869751/3068190) and the older [`FirebaseAuthUserContext`](https://stackoverflow.com/revisions/68871889/3) may also be of use to read through. – samthecodingman Jan 05 '23 at 04:07
  • thank you for the help and correction, I will read the previous thread that you have provided – Lavigne Jan 05 '23 at 04:36