Why does this not print anything on website React.js?

Viewed 41

I'm quite new to web development, I am wondering why when I call readContacts() in Contacts.js why the readContacts() function for ContactsContext.js does not output the return to my website? Thank you in advanced.

ContactsContext.js
import React, { useContext } from "react"
import { db } from "../firebase"

import { useAuth } from "./AuthContext"

const ContactsContext = React.createContext()

export function useContacts() {
  return useContext(ContactsContext)
}

export function ContactsProvider({ children }) {
  const { currentUser } = useAuth()

  function createContact(email, firstName, lastName) {
    db.ref("users/" + currentUser.uid + "/contacts/" + firstName + " " + lastName).set({
      Email: email,
      FirstName: firstName,
      LastName: lastName
    })
  }

  function readContacts() {
    db.ref("users/" + currentUser.uid + "/contacts/").on("value", (snapshot) => {
      return (snapshot.val())
    })
  }

  const value = {
    createContact,
    readContacts
  }

  return (
    <ContactsContext.Provider value={value}>
      {children}
    </ContactsContext.Provider>
  )
}
Contacts.js
import React from "react"
import { ListGroup } from "react-bootstrap"

import { useContacts } from "../contexts/ContactsContext"
  
export default function Contacts() {
  const { readContacts } = useContacts()

  return (
    <ListGroup variant="flush">
      <ListGroup.Item>
        { readContacts() }
      </ListGroup.Item>
    </ListGroup>
  )
}
1 Answers

readContacts function isn't returning anything. But even if you did add return db.ref(..... in the function, you're calling it in the render return. This won't work since React renders are synchronous, pure functions (without side-effects).

Typically you should setup these subscriptions in an useEffect hook and typically you'd update some local state with the snapshot value. Your code is so far from this it's difficult to say what your goal is. My best guess is that you want some contacts state in ContactsProvider and you should be providing this out to the app.

const ContactsContext = React.createContext({
  // Don't forget to provide default context value
  contacts: [],
  createContact: () => {},
});

export function useContacts() {
  return useContext(ContactsContext);
}

export function ContactsProvider({ children }) {
  const { currentUser } = useAuth();
  const [contacts, setContacts] = useState([]); // <-- add state

  function createContact(email, firstName, lastName) {
    db.ref("users/" + currentUser.uid + "/contacts/" + firstName + " " + lastName).set({
      Email: email,
      FirstName: firstName,
      LastName: lastName
    })
  }

  useEffect(() => {
    db.ref("users/" + currentUser.uid + "/contacts/")
      .on(
        "value",
        snapshot => setContacts(snapshot.val()), // <-- update state
      );

    // NOTE: you likely need to also unsubscribe when component unmounts
  }, []);

  const value = {
    createContact,
    contacts, // <-- provide contacts state
  }

  return (
    <ContactsContext.Provider value={value}>
      {children}
    </ContactsContext.Provider>
  )
}

Now context consumers access the contacts array value and render accordingly.

const { contacts } = useContacts();

...

contacts.map(contact => .....
Related