Why am I getting “undefined” even though there is a value being returned in React with Firebase Realtime DB?

I am using Firebase for my small React-driven web app. I setup my Firebase configuration and added some data to Firebase Realtime Database. My data in Firebase is setup like so:

{
  "matches" : {
    "ace34187-c7f2-41e7-a7f2-f097963cddc5" : {
      "questions" : [ {
        "answers" : [ {
          "answer" : "4",
          "isCorrect" : true
        }, {
          "answer" : "2",
          "isCorrect" : false
        }, {
          "answer" : "12",
          "isCorrect" : false
        }, {
          "answer" : "6",
          "isCorrect" : false
        } ],
        "question" : "What is two plus two?",
        "type" : "multi-choice-answer"
      } ]
    }
  },
  "sessions" : {
    "9d82c839-b3e1-474a-a084-61141293efa3" : {
      "code" : "1234",
      "rootMatch" : "ace34187-c7f2-41e7-a7f2-f097963cddc5",
      "teams" : {
        "9d82c839-b3e1-474a-a084-61141293efa3" : {
          "emoji" : "1f34f",
          "name" : "Apples",
          "score" : 0,
          "strikes" : 0
        },
        "dc550e48-5bc5-4e6c-bfef-c6626cf6d94b" : {
          "emoji" : "1f4a9",
          "name" : "Pickles",
          "score" : 0,
          "strikes" : 0
        }
      }
    }
  }
}

I have set up a state for match which initializes with an empty object:

const [match, setMatch] = useState({});

Each match has an array of questions which have corresponding answers and a type. I am fetching these matches from Firebase Realtime Database using the below function:

const getMatch = () => {
    return onValue(
      ref(db, "/matches/ace34187-c7f2-41e7-a7f2-f097963cddc5"),
      (snapshot) => {
        console.log(snapshot.val());
        setMatch(snapshot.val());
      },
      {
        onlyOnce: true,
      }
    );
  };

This function is then being called via the useEffect React Hook with an empty dependency list as seen in the below code:

useEffect(() => {
    getMatch();
  }, []);

Next, I want to fetch the match data and place it into my JSX code similar to this:

return (
    <div className="App">
      <h1>{match.questions[0].question}</h1>
      <AnswerBox question={match.questions[0]} />
    </div>
  );

When I setup all of this code I end up with an error:

TypeError: match.questions is undefined

I logged match to the console to see if it has any value or was returning as undefined and this is what I got returned:

Object {  }
Object {  }
Object { questions: (1) […] }
​
questions: Array [ {…} ]
​​
0: Object { answers: (4) […], question: "What is two plus two?", type: "multi-choice-answer" }
​​
length: 1
​​
<prototype>: Array []
​
<prototype>: Object { … }

Why is match returning two empty objects and then returning an object with values. Also, why do I receive the type error if match is not undefined.

Answer

The initial state for match is {} so match.questions is indeed undefined. Try changing the initial state to:

const [match, setMatch] = useState({ questions: [] })

Also try removing return since onValue returns a function to unsubscribe from the listener anyway:

const getMatch = () => {
  onValue(ref(db, "/matches/ace34187-c7f2-41e7-a7f2-f097963cddc5"), (snapshot) => {
    console.log(snapshot.val());
    setMatch(snapshot.val());
  }, {
    onlyOnce: true,
  });
};