简体   繁体   中英

Is React Router causing my component to render twice?

Background

I have a list of items. If you click on a detail link under an item, you are taken to its page where it allows you to read and add comments about that particular item. Currently, the comments component is rendering both on the index page and on the item details page . It should only render on the latter.

Can you help me figure out why?

Troubleshooting

I checked my routes and my Comments and Comment components but did not see any obvious errors. I saw this post about rendering components twice, but my situation is different because I have to use render= to pass down props.

I'll admit, I have never tried to build a route like this, so maybe I am not approaching it properly. The one is question is the 2nd from the bottom in this list below.

Routes

  render(){
    return(
      <div>
        <Switch>
          <Route exact path='/' render={(routerProps) => <Programs {...routerProps} programs={this.props.programs}/>} /> />
          <Route exact path='/programs' render={(routerProps) => <Programs {...routerProps} programs={this.props.programs} />} />
          <Route path='/programs/new' render={(routerProps) => <ProgramInput {...routerProps}/>}/>
          <Route path='/programs/:id' render={(routerProps) => <Program {...routerProps} programs={this.props.programs}/>}/>
          <Route exact path='/programs/:id/comments' render={(routerProps) => <Program {...routerProps} program={this.props.program}/>}/>
          <Route exact path='/watchlist' render={(routerProps) => <Program {...routerProps} programs={this.props.programs} />} />
        </Switch>
      </div>
    )
  }

CommentsContainer

class CommentsContainer extends React.Component {
  render(){
    return(
      <div>
        <Comments comments={this.props.program && this.props.program.comments}/>
      </div>
    )
  }
}

export default CommentsContainer

Program (where CommentsContainer is rendered)

I took out some of the Card code for brevity. There is More link inside the card that takes you to the item page. That part works fine.

return(
        <Fragment>
          <Grid.Column>
            <Card as='div'>
             </Card>
          </Grid.Column>

          <CommentsContainer program={program}/>

        </Fragment>
      )
    }

Comments

const Comments = (props) => {
  // console.log(props.comments && props.comments.map(comment => console.log(comment))
  return(
    <Comment.Group>


      {props.comments && props.comments.map(comment => <CommentCard key={comment.id} comment={comment}/>)}


    </Comment.Group>
  )
}

export default Comments

ComentCard I don't think the issue lies here, but here's a link if you need to see the file.

Backend

I am using Rails API for my backend. Here is a link to my comments_controller if you want to take a peek.

Thank you for your time and advice!

如果只希望在有CommentsContainer时显示CommentContainer,则可以将其呈现的行替换为:

{program.comments && <CommentsContainer program={program}/>}

As Matt Oestreich pointed out earlier you always render comments when you render the Program component. The Programs (plural) component is basically a list that consists of Program components. So when you render the Programs component you always render the CommentsContainer with the Comment Component.

So maybe you can make another component, the ProgramDetails Component where you include the CommentsContainer. In the Program Component you can link to the ProgramDetails Component. I think this would prevent that the comments render in the Programs (plural) is rendered.

This did end up being a routes issue. Both my /programs and my / routes were displaying my CommentsContainer because I needed to add a ternary to essentially filter those routes out.

I added this code in my Programs (plural) component right after my Card component. It uses props.match to check if the route being rendered was NOT /programs and NOT / . When that statement evaluated to true, the CommentsContainer and associated comments were rendered on the /programs/:id . If either of those statements evaluated to true, it didn't render anything.

{this.props.match.url !== '/programs' && this.props.match.url !== '/'? <CommentsContainer program={program}/> : null}

Since I only passed down routerProps in my Programs.js file, I had to pass down props.match from Programs to my Program component (which renders the cards and CommentContainer). Doing this allows the ternary above to work.

{props.programs && props.programs.map((program) => <Program key={program.name} program={program} match={props.match}/>)}

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