Passed-down props rendering undefined on first page load?

Viewed 24

I have a site that is rendering cards of music artists then allowing the user to click on a button "View Ticket Activity" on each artist's card, which then allows more information to show up. Styled using Tailwind (the class names) and using react-router-v6.

I defined my artists state to successfully pull all the seeded artists from a rails DB and I output these artists all at once via a component called <ArtistsDisplay /> (which is routed to '/artists', where I pass down artists={artists} from the parent component <App />. In <ArtistsDisplay />, each artist maps out.

I have a separate component called <EachArtistCard /> that is routed (in <App />) to '/artists/:id' and is redirected there by a useNavigate() within <ArtistDisplay />. The problem there is that artist passes down from the parent <ArtistDisplay /> to the child <EachArtistCard /> and thisArtist=undefined on the first pass, which then breaks the map function within <EachArtistCard />. I'm defining it as thisArtist in place of artist within as a just in case to not have conflict name-wise with the const thisArtist = artists.find( (artist) => parseInt(id) === parseInt(artist.id) );

Within <ArtistsDisplay /> is my major issue. I've tried many re-writes (replacing the new component with an in-component modal, reconfiguring routes, etc) but fundamentally I need to understand why I have the thisArtist=undefined rendering issue. I'm not in strictMode (afaik) as I've seen the double-render-in-development posts so it's gotta be my error somewhere in my writing of this app.

ArtistsDisplay.js

function ArtistsDisplay({ artists, user, searchTerm, setSearchTerm }) {
  let navigate = useNavigate();

  return (
    <div class='bg-base-900 py-6 sm:py-8 lg:py-12'>
      <div class='form-control'>
        <label class='flex input-group input-group-lg'>
          <span>SEARCH</span>
          <input
            type='text'
            onChange={(e) => setSearchTerm(e.target.value)}
            placeholder='Search for your favorite artists here...just start typing'
            class='input input-bordered w-full input-lg text-center'
          />
        </label>
      </div>
      <div>
        <div class='mx-auto max-w-screen-xl px-4 md:px-8'>
          <div class='mb-10 md:mb-16'>
            <h1 class='mb-4 text-center text-6xl font-thin text-primary md:mb-6 lg:text-7xl'>
              ARTISTS
            </h1>
            <p class='mx-auto uppercase text-center max-w-screen-md text-secondary text-gray-500 md:text-lg'></p>
          </div>
          <div class='grid gap-8 mx-6 sm:grid-cols-2 sm:gap-12 lg:grid-cols-3 '>
            {artists
              .filter((artist) => {
                if (searchTerm === '') {
                  return artist;
                } else if (
                  artist.name.toLowerCase().includes(searchTerm.toLowerCase())
                ) {
                  return artist;
                }
              })
              .map((artist) => (
                <div>
                  <div
                    key={artist.id}
                    class='card w-96 max-w-xs bg-neutral text-neutral-content shadow-xl'>
                    <div class='card-body p-4 m-2 mx-0 items-center text-center'>
                      <div class='avatar'>
                        <div class='w-30 rounded'>
                          <img
                            src={artist.image}
                            alt='a small avatar of the musical artist'
                          />
                        </div>
                      </div>
                      <h1 class='card-title'>{artist.name}</h1>
                      <p>{artist.genre.name}</p>
                      <div class='card-actions justify-end'>
                        <button
                          class='btn btn-primary'
                          onClick={() => navigate(`/artists/${artist.id}`)}>
                          view ticket activity
                        </button>
                      </div>
                    </div>
                  </div>
                </div>
              ))}
          </div>
        </div>
      </div>
    </div>
  );
}

export default ArtistsDisplay;

EachArtistCard.js
note: even with the two useEffects below commented out, thisArtist still =undefined

import React from 'react';
import { useParams } from 'react-router-dom';
import { useEffect, useState } from 'react';
import IndividualPost from './IndividualPost';

    function EachArtistCard({ posts, setPosts, artists }) {
      let { id } = useParams();
 const thisArtist = artists.find(
        (artist) => parseInt(id) === parseInt(artist.id)
      );
   
    
    //* to set selling & looking
  useEffect(() => {
    thisArtist.posts.map((each) => {
      if (each.for_sale === true) {
        setSelling(selling + 1);
      } else {
        setLooking(looking + 1);
      }
    });
  }, []);

  //* to set upcomingShows
  useEffect(() => {
    thisArtist.concerts.map((each) => setUpcomingShows(upcomingShows + 1));
  }, []);
    
     
      return (
        <div>
          <div class='bg-base-900 py-6 sm:py-8 lg:py-'>
            <div class='mx-auto max-w-screen-xl px-4 md:px-8'>
              <div class='mb-10 md:mb-16'>
                <h1 class='mb-4 text-center text-6xl font-thin uppercase text-primary md:mb-6 lg:text-7xl'>
                  {thisArtist.name}
                </h1>
              </div>
    
              <div class='flex justify-center'>
                <div class='card w-96 bg-base-500 bg-neutral text-neutral-content justify-center shadow-2xl'>
                  <div class='avatar'>
                    <div class='w-30 rounded'>
                      <img
                        src={thisArtist.image}
                        alt='a small avatar of the music thisArtist'
                      />
                    </div>
                  </div>
                  <div class='card-body items-center text-center'>
                    <h2 class='card-title'>{thisArtist.name}</h2>
                    <p>
                      There's {upcomingShows} upcoming concerts listed for{' '}
                      {thisArtist.name}!
                    </p>
                    <div>
                      <div class='badge badge-primary uppercase'>
                        {selling} selling
                      </div>
                      <div class='badge badge-primary uppercase'>
                        {looking} looking
                      </div>
                    </div>
                    <div class='card-actions justify-end'>
                      <button class='btn btn-secondary w-full'>
                        I have tickets to sell
                      </button>
                      <button class='btn btn-secondary w-full'>
                        I'm Looking For Tickets
                      </button>
                      <button class='btn btn-outline btn-black w-full'>
                        Go Back
                      </button>
                    </div>
                  </div>
                </div>
              </div>
              <h2 class='my-10 text-center text-5xl font-thin uppercase text-primary md:mb-6 lg:text-6xl'>
                ALL POSTS
              </h2>
            </div>
          </div>
        </div>
      );
    }
    
    export default EachArtistCard;

App.js
removed a lot of other code not pertaining to the situation here

 import '../../src/App.css';
    import ArtistsDisplay from './ArtistsDisplay';
    import ConcertsDisplay from './ConcertsDisplay';
    import VenuesDisplay from './VenuesDisplay';
    import GenreDisplay from './GenreDisplay';
    import Login from './Login';
    import SignUp from './SignUp';
    import NotFound from './NotFound';
    import Header from './Header';
    import { Route, Routes } from 'react-router-dom';
    import { useState, useEffect } from 'react';
    import UsersPage from './UsersPage';
    import EachArtistCard from './EachArtistCard';
    
    function App() {
    
      const [user, setUser] = useState('');
      const [sessionInfo, setSessionInfo] = useState([]);
      
    
      const [searchTerm, setSearchTerm] = useState('');
      const [artists, setArtists] = useState([]);
     
      useEffect(() => {
        fetch('/artists')
          .then((r) => r.json())
          .then((info) => setArtists(info));
      }, []);
     
      return (
        <div>
          <Header
            user={user}
            setUser={setUser}
            onLogin={onLogin}
            onLogout={onLogout}
            loggedIn={loggedIn}
          />
          <Routes>
            <Route
              path='/'
              element={
                <UsersPage
                  user={user}
                  cookies={cookies}
                  sessionInfo={sessionInfo}
                  loggedIn={loggedIn}
                />
              }
            />
            <Route
              path='/artists'
              element={
                <ArtistsDisplay
                  artists={artists}
                  genres={genres}
                  user={user}
                  posts={posts}
                  setPosts={setPosts}
                  searchTerm={searchTerm}
                  setSearchTerm={setSearchTerm}
                  showModal={showModal}
                  setShowModal={setShowModal}
                />
              }
            />
            <Route
              path='/artists/:id'
              element={
                <EachArtistCard
                  artists={artists}
                  concerts={concerts}
                  posts={posts}
                  setPosts={setPosts}
                  user={user}
                />
              }
            />
            <Route path='*' element={<NotFound />} />
          </Routes>
        </div>
      );
    }
    
    export default App;

Will take any steps in the right direction as I'm lost. If more info is needed, please let me know.

0 Answers
Related