简体   繁体   中英

useState hook is breaking activePost as useEffect is triggered by selectedPost

My goal was to fetch posts from Graphcms and populate an array - posts, and populate it into postlist, then the main component will change according to what the user clicks on a post from postlist, I can see the posts array is populated, but when i click on a post on postlist I get the following error

Main.js:22 Uncaught TypeError: Cannot read properties of undefined (reading 'featuredImage') Below my files

App.js

function App() {

 const [selectedPost,setSelectedPost] = useState(0);
 const [posts, setPosts] = useState([]);


 useEffect(() => {
   const fetchPosts = async () => {
     const { posts } = await request(
       'https://api-ap-southeast-2.graphcms.com/v2/ckxo1np9m5kw601xpccps4lrn/master',
       `
     { 
       posts {
         id
         title
         slug
         excerpt
         featuredImage
         {
           url
        }
       }
     }
   `
     );
     console.log("print posts " , posts)
     setPosts(posts);
   };

   fetchPosts();
 }, []);

  return ( <div className='app'>
    <Header/>
    {
      posts.length>0 && (<>
        <Main posts={posts} selectedPost={selectedPost}/>  
        <PostList posts={posts} setSelectedPost={setSelectedPost} />
        </>
      )
    }

  
  </div>
  )
}

export default App;

And the Main.js Component

const Main = ({selectedPost,posts}) => {

    const[activePost,setActivePost] =useState(posts[0])
    console.log("activePost ", activePost)

    useEffect(()=>{
      setActivePost(posts[selectedPost])
    },[posts,selectedPost])
  


    return (
        <div className='main'>
            <div className='mainContent'>
                <div className='postHighlight'>
                    <div className='postContainer'>
                    <img 
                    className='selectedPost'
                    src= {activePost.featuredImage.url}
                    alt=''
                    />
                </div>
                </div>
            
            <div className='postDetails' style={{color:'#fff'}}>
                <div className='title'>
                   {activePost.title} </div>
                    <span className='itemNumber'></span>
                    <span className='postExcerpt'>{activePost.excerpt}</span>
                 
                </div>

           <div className='otherDetails'>
           
          </div>
        </div>
        </div>
    )
}

export default Main

And then we have postList.js file

const PostList = ({posts,setSelectedPost}) => {
    return (
        <div className='postList'>
            {posts.map(post=>(
                    <div onClick={()=>setSelectedPost(post.id)}>
                        <CollectionCard key={post.slug} title={post.title} excerpt={post.excerpt} imageSrc={post.featuredImage.url}/>

                    </div>
             )) })
            
        </div>
    )
}

export default PostList

Based on your app, you are using the index of the selected post. The error arises from your onclick function. You are passing post.id to setSelectedPost() so you are accessing the posts array incorrectly. Hence, the undefined . Just use the current index on your map function:

<div className='postList'>
  {posts.map((post, index) => (
     <div onClick={() => setSelectedPost(index)} key={post.slug}>
       <CollectionCard
          title={post.title}
          excerpt={post.excerpt}
          imageSrc={post.featuredImage.url}
       />
     </div>
    ))
   }         
</div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM