Lara Calvo
Lara Calvo

Reputation: 43

React runs an infinite loop when updating real time database

import React, { useState } from 'react';
import { ref, onValue, update} from "firebase/database";
import { database } from '../../utils/firebase';
import './Card.css';



function Card(props) {
    const [uid, setUID] = useState(props.uid);
    function completeCard() {
        const userRef = ref(database, 'users/' + uid);
          onValue(userRef, (snapshot) => {
            const data = snapshot.val();
            var completedMissions = data["challenges"];
            completedMissions.push(props.cardID);
            
            const updates = {};
            updates['/user/' + uid +'/challenges'] = completedMissions;
            //This is the line causing the infinite loop
            update(ref(database), updates);
            
          });
          
    }
    return(
        <div className="card">
            <h1>{props.name}</h1>
            <p>{props.description}</p>
            <button onClick={completeCard}>Complete</button>
            <button>+Info</button>
        </div>
    )
}
export default Card;

Hi, when I'm trying to update the value in the firebase real time database, it causes an infinite loop! I think that the onValue may be causing the problem but I don't know how to fix it. I would like when the button is pressed to only update the value once, as it only should change once, thank you in advance!

Upvotes: 2

Views: 540

Answers (1)

Nicholas Tower
Nicholas Tower

Reputation: 84902

onValue sets up a listener which will repeatedly call you back, every time that part of the database changes. So it gets data for the first time and runs your code. Your code updates the database, so the callback happens again, which causes you to update the database again. Repeat.

If you just want to get the value once, use get instead:

import { ref, get, update } from "firebase/database";

//...
function completeCard() {
  const userRef = ref(database, "users/" + uid);
  get(userRef).then((snapshot) => {
    const data = snapshot.val();
    const completedMissions = data["challenges"];
    completedMissions.push(props.cardID);

    const updates = {};
    updates["/user/" + uid + "/challenges"] = completedMissions;
    update(ref(database), updates);
  });
}

Or with async/await:

async function completeCard() {
  const userRef = ref(database, "users/" + uid);
  const snapshot = await get(userRef);
  const data = snapshot.val();
  const completedMissions = data["challenges"];
  completedMissions.push(props.cardID);

  const updates = {};
  updates["/user/" + uid + "/challenges"] = completedMissions;
  update(ref(database), updates);
}

Upvotes: 3

Related Questions