Home > Enterprise >  Dynamically rendering child components in react
Dynamically rendering child components in react

Time:12-25

I'm using firestore database to store my data in the collection "listings". So for each document in "listings", I need to render a <BookListing/> element in Home.js with the data from each document. From my research, there are a few other questions similar to this one out there, but they're outdated and use different react syntax. Here's my code:

function BookListing({id, ISBN, title, image, price}) {
    
    return (
        <div className="bookListing">
            <div className='bookListing_info'>
                <p className="bookListing_infoTitle">{title}</p>
                <p className="bookListing_infoISBN"><span className="bookListing_infoISBNtag">ISBN: </span>{ISBN}</p>
                <p className="bookListing_infoPrice">
                    <small>$</small>
                    {price}
                </p>
            </div>
            <img className="bookListing_img" src={image} alt=""></img>
            <button className="bookListing_addToCart">Add to Cart</button>
        </div>
    )
}

export default BookListing

function Home() {

    document.title ="College Reseller";

    useEffect(() => {
        getDocs(collection(db, 'listings'))
        .then(queryCollection => {
            queryCollection.forEach((doc) => {
                console.log(doc.id, " => ", doc.data());
                const element = <BookListing id="456" ISBN="0101" title="sample_title" image="https://nnpbeta.wustl.edu/img/bookCovers/genericBookCover.jpg" price="25"/>;
                ReactDOM.render(
                    element,
                    document.getElementById('home-contents-main')
                );
            })
        });
    }, []);



    return (
        <div className="home">
            <div className="home_container">
                <div id="home-contents-main" className="home_contents">
                </div>
            </div>
        </div>
    )
}
export default Home

CodePudding user response:

It's best (and most common) to separate the task into two: asynchronously fetching data (in your case from firestore), and mapping that data to React components which are to be displayed on the screen.

An example:

function Home() {
  // A list of objects, each with `id` and `data` fields.
  const [listings, setListings] = useState([]) // [] is the initial data.

  // 1. Fetching the data

  useEffect(() => {
    getDocs(collection(db, 'listings'))
      .then(queryCollection => {
        const docs = [];
        queryCollection.forEach((doc) => {
          docs.push({
            id: doc.id,
            data: doc.data()
          });

          // Update the listings with the new data; this triggers a re-render
          setListings(docs);
        });
      });
  }, []);

  // 2. Rendering the data

  return (
    <div className="home">
      <div className="home_container">
        <div className="home_contents">
          {
            listings.map(listing => (
              <BookListing
                id={listing.id}
                ISBN={listing.data.ISBN}
                title={listing.data.title}
                image={listing.data.image}
                price={listing.data.price}
              />
            ))
          }
        </div>
      </div>
    </div>
  );
}

Some tips:

  • Fetching data from other web servers or services can be, and typically is, done in the same manner.
  • This example could be improved a lot in terms of elegance with modern JS syntax, I was trying to keep it simple.
  • In most cases, you don't want to use ReactDOM directly (only for the entry point of your app), or mess with the DOM manually; React handles this for you!
  • If you're not familiar with the useState hook, read Using the State Hook on React's documentation. It's important!

CodePudding user response:

You can create a reusable component, and pass the data to it, and iterate over it using map() . define a state, and use it within the useEffect instead of creating elements and handling the process with the state as a data prop.

function BookListing({ id, ISBN, title, image, price }) {
  return (
    <div className="bookListing">
      <div className="bookListing_info">
        <p className="bookListing_infoTitle">{title}</p>
        <p className="bookListing_infoISBN">
          <span className="bookListing_infoISBNtag">ISBN: </span>
          {ISBN}
        </p>
        <p className="bookListing_infoPrice">
          <small>$</small>
          {price}
        </p>
      </div>
      <img className="bookListing_img" src={image} alt=""></img>
      <button className="bookListing_addToCart">Add to Cart</button>
    </div>
  );
}

function Home() {
  const [data, setData] = useState([]);

  useEffect(() => {
    document.title = 'College Reseller';
    getDocs(collection(db, 'listings')).then((queryCollection) => setData(queryCollection));
  }, []);

  return (
    <div className="home">
      <div className="home_container">
        <div id="home-contents-main" className="home_contents">
          {data.map((doc) => (
            <BookListing
              id="456"
              ISBN="0101"
              title="sample_title"
              image="https://nnpbeta.wustl.edu/img/bookCovers/genericBookCover.jpg"
              price="25"
            />
          ))}
        </div>
      </div>
    </div>
  );
}
export default Home;
  • Related