Home > Software engineering >  React child component using layered map methods on layered objects and arrays does not re-render whe
React child component using layered map methods on layered objects and arrays does not re-render whe

Time:08-28

I have a component I am working on where the parent passes in a particular prop from its state. The prop is an array where each element of the array contains sub object that contains its own array.

import react, {useState} from 'react';
import Posts from './Posts';

function App() {
  const [posts, setPosts] = useState([
    {title: 'post1',data:{comments:['comment1', 'comment2','comment3']}},
    {title: 'post1',data:{comments:['comment1', 'comment2','comment3']}},
    {title: 'post1',data:{comments:['comment1', 'comment2','comment3']}},
  ])

  const deleteComment = (postIndex, commentIndex) =>{
    let newPosts = [...posts];
    newPosts[postIndex].comments.splice(commentIndex, 1);
    setPosts(newPosts);
  }

  return (
    <>
      <h1>Parent Component</h1>
      <Posts posts={posts} deleteComment={deleteComment}  />
    </>
  );
}

export default App;

This prop gets passed down to a child component that then also receives a delete Comment Function. When that function is fired, the comment is deleted from state. However, when the props are updated, the child component does not re-render. My understanding is that React only looks at the top array and its top level elements to note if it re-renders, and does not catch a change at this depth in the object. What is the best way to make my child component re-render when the delete comment function is fired?

import React from 'react'

export default function Posts({posts, deleteComment}) {
    console.log('posts: ', posts)
  return (
    <>
    <h2>Posts</h2>
    {posts.map((post, postIndex)=>{
        return(
            <div key={post.title}>
            <h3>{post.title}</h3>
            {post.data.comments.map((comment, commentIndex)=>{
                return(<><p>{comment}</p> 
                <button onClick={()=>{deleteComment(postIndex,commentIndex)}}>Delete</button></>)
                
            })}
            </div>)}
        )
        
    })
    </>
    
  )
}

I should also note this is a simplified example of something I'm working on for an employer, so taking comments out of data, and putting it in each post is not doable in the project I'm working on.

CodePudding user response:

you missed the data prop. try this :

  const deleteComment = (postIndex, commentIndex) =>{
    let newPosts = [...posts];
    newPosts[postIndex].data.comments.splice(commentIndex, 1);
    setPosts(newPosts);
  }

it is also advisable to use filter which is not mutate the old state and it is always create new array

CodePudding user response:

Array.splice mutates the array itself instead of creating a new one. When you call setState you're passing in the same array reference so a change is not detected. Use .filter instead and set a new array to state.

  • Related