Home > database >  React conditional rendering confusion
React conditional rendering confusion

Time:06-12

I have an application that gets data from an API. I'm trying to use conditional rendering so that if now data was not retrieved from the API display a message. The problem is that both of my states are set as empty arrays, and the condition I am using is arryname.length === 0. Every time my application renders the arrays initialize to a length of 0 so the message flashs the screen quickly then go away once the data is retrieved from the API. Any ideas on how to best solve this issue?

Thanks

import React, { useState, useEffect } from "react";
import {
  NavBar,
  Footer,
  Home,
  About,
  Projects,
  TextareaAutosize,
  ToastContainer,
  toast,
} from "./imports";
import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
import { db } from "./firebase-config";
import {
  collection,
  doc,
  updateDoc,
  addDoc,
  Timestamp,
  query,
  orderBy,
  onSnapshot,
} from "firebase/firestore";

export default function App() {
  const [formData, setFormData] = useState({ name: "", comment: "" });
  const [numberOfVisitors, setnumberOfVistors] = useState([]);
  const [userComments, setUserComments] = useState([]);

  const userCommentsRef = collection(db, "user-comments");

  const addNewComment = async (event) => {
    event.preventDefault();
    if (formData.name === "") {
      const nameFieldErrorMessage = toast.error(" Error: Please Enter A Name", {
        position: "top-right",
        hideProgressBar: true,
        autoClose: false,
      });
      return nameFieldErrorMessage;
    }

    if (formData.comment === "") {
      const commentFieldErrorMessage = toast.error(
        " Error: Please Enter A Comment",
        {
          position: "top-right",
          hideProgressBar: true,
          autoClose: false,
        }
      );
      return commentFieldErrorMessage;
    }

    const commentSuccessMessage = toast.success(" Comment Posted!", {
      position: "top-right",
      hideProgressBar: true,
      autoClose: false,
    });

    const newComment = {
      name: formData.name,
      comment: formData.comment,
      date: Timestamp.now(),
    };

    setFormData({ name: "", comment: "" });

    try {
      await addDoc(userCommentsRef, newComment);
      return commentSuccessMessage;
    } catch (err) {
      console.log(err);
    }
  };

  const handleFormData = (event) => {
    setFormData((prevFormData) => {
      return {
        ...prevFormData,
        [event.target.name]: event.target.value,
      };
    });
  };

  useEffect(() => {
    const portfolioStatsRef = collection(db, "portfolio-stats");
    const q = query(portfolioStatsRef);
    const unsubscribeFromEventListener = onSnapshot(q, (snapshot) => {
      const VisitorCountFromDB = snapshot.docs.map((doc) => ({
        ...doc.data(),
        id: doc.id,
      }));
      setnumberOfVistors(VisitorCountFromDB);
    });

    return () => unsubscribeFromEventListener();
  }, []);

  useEffect(() => {
    const updateVisitorCount = async () => {
      try {
        const portfolioStatsDoc = doc(
          db,
          "portfolio-stats",
          numberOfVisitors[0].id
        );
        const updatedFields = {
          visitor_count: numberOfVisitors[0].visitor_count   1,
        };
        await updateDoc(portfolioStatsDoc, updatedFields);
      } catch (err) {
        console.log(err   " at updateVisitorCount function");
      }
    };

    if (!numberOfVisitors.length) return;

    let sessionKey = sessionStorage.getItem("sessionKey");

    if (sessionKey === null) {
      sessionStorage.setItem("sessionKey", "randomString");
      updateVisitorCount();
    }
  }, [numberOfVisitors]);

  useEffect(() => {
    const q = query(userCommentsRef, orderBy("date", "asc"));
    onSnapshot(q, (snapshot) => {
      const userCommentsFromDB = snapshot.docs.map((doc) => ({
        ...doc.data(),
        id: doc.id,
      }));
      setUserComments(userCommentsFromDB);
    });
  }, [userCommentsRef]);

  const currentNumberOfVisitors = numberOfVisitors.map((visitors) => {
    return (
      <h2 className="p-3 mb-0 bg-dark bg-gradient text-white" key={visitors.id}>
        Number of vistors: {visitors.visitor_count}
      </h2>
    );
  });

  const listOfUserComments = userComments.map((comment) => {
    return (
      <li className="list-group-item" key={comment.id}>
        <div className="d-flex w-100 justify-content-between">
          <h5 className="ms-1">{comment.name}</h5>
          <small className="fw-bold">
            {comment.date.toDate().toLocaleString()}
          </small>
        </div>
        <p className="mb-1">{comment.comment}</p>
      </li>
    );
  });

  return (
    <>
      <div className="d-flex flex-column overflow-hidden min-vh-100 vh-100">
        <NavBar />
        <div className="row">
          <div className="col text-center">
            {currentNumberOfVisitors.length === 0 && (
              <h2 className="p-3 mb-0 bg-dark bg-gradient text-danger">
                Sorry, the Firestore free tier quota has been met for today.
                Please come back tomorrow to see portfilio stats.
              </h2>
            )}
            {currentNumberOfVisitors}
          </div>
        </div>
        <div className="bg-image">
          <div className="postion-relative">
            <main className="flex-grow-1">
              <div className="container-fluid p-0">
                <Router>
                  <Routes>
                    <Route path="/" element={<Home />} />
                    <Route path="/about" element={<About />} />
                    <Route path="/projects" element={<Projects />} />
                  </Routes>
                  <div className="row">
                    <div className="center-items col">
                      <h2 className="text-light fw-bold mb-1">Comments</h2>
                    </div>
                  </div>
                  <div className="row">
                    <div className="center-items col">
                      <div className="comments-container">
                        {userComments.length === 0 && (
                          <h4 className="text-danger bg-dark m-1 p-1">
                            Sorry, the Firestore free tier quota has been met
                            for today. Please come back tomorrow to see
                            portfilio comments.
                          </h4>
                        )}
                        {listOfUserComments}
                      </div>
                    </div>
                  </div>
                  <div className="row">
                    <div className="center-items col">
                      <h4 className="text-light fw-bold">Leave a comment</h4>
                    </div>
                  </div>
                  <div className="row">
                    <div className="center-items col">
                      <form className="comment-form">
                        <div className="form-floating mb-3">
                          <input
                            type="text"
                            className=" form-control bg-transparent "
                            id="floatingInput"
                            name="name"
                            onChange={handleFormData}
                            value={formData.name}
                          />
                          <label htmlFor="floatingInput">Name</label>
                        </div>
                        <div className="form-floating">
                          <TextareaAutosize
                            className="form-control form-textarea-field bg-transparent  mb-1"
                            name="comment"
                            id="floatingTextarea"
                            minRows={4}
                            onChange={handleFormData}
                            value={formData.comment}
                          />
                          <label htmlFor="floatingTextarea">Comment</label>
                        </div>
                        <div className="d-grid">
                          <button
                            className="btn btn-primary mb-4"
                            onClick={addNewComment}
                          >
                            Add Comment
                          </button>
                        </div>
                      </form>
                    </div>
                  </div>
                </Router>
              </div>
            </main>
          </div>
        </div>
        <Footer />
      </div>
      <ToastContainer />
    </>
  );
}

CodePudding user response:

Usually, you use a boolean flag to signal if your API call is still in progress. If it is, don't display the error.

const [isLoading, setIsLoading] = useState(true);

Set this flag to false when your API call has completed:

setIsLoading(false);

Then in your rendering logic:

{(!isLoading && currentNumberOfVisitors.length === 0) && (
  <h2 className="p-3 mb-0 bg-dark bg-gradient text-danger">
    Sorry, the Firestore free tier quota has been met for today.
    Please come back tomorrow to see portfilio stats.
  </h2>
)}
  • Related