Karan
Karan

Reputation: 1151

Using a function in the render state in ReactJS to append a div to another

I was messing around and creating a comment like tree structure, which works out fine except when I want to get into creating collapsing and expanding commenting trees. So far the display is well, it is displayed on my webpage in proper tree structure, just like reddit, however I want to build in a collapse and expand comments and subcomments feature. I have an idea of using jquery to appending a div as soon as it is finished rendering. What comes to mind when i think about it is:

         var childDiv = "#" + comment._id;
         var parentDiv = "#" + comment.pComment;


         $(parentDiv).append(childDiv);

This is my idea of appending divs together, where pComment holds the parentComments id, and I already establish my divs with the id of themselves as soon as they are mapped/rendered. However the issue is how do I tell my render function this is what I want to do at the end of each render mapping. I map a comment at a time, and I create the div there, so obviously it cant map to that div if it isnt there, and this is where I get lost. I tried out the idea with making it a onclick function and worked out great, but I would like for it to append on each mapping, and at the end of it after the div is rendered, so it appends the div's in correct order. I think there's alot of differents way to go about this but I'm not sure how.

render : function() {
      return( 

          <div>
          <ul className = "list-unstyled">
          {
          this.props.comments.map(function(comment) {
            return(


            //Right here is what I want to append to another div.
            <div id = {comment._id}>
            <div className = "userComments">
            //content
            </div>
            </div>
            )


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

Generally my goal is to create a parent div, and append to it any div that holds its children.

I've tried doing var x = $(parentDiv).append(childDiv); and then I proceeded to call {x} in between the div so it would append it. For the parent case, pComment is defaulted to the id ROOT, every comment that is owned by that comment after has its 'pComment' value held by its owners id.

However doing so I get

Uncaught Error: Invariant Violation: traverseAllChildren(...): Encountered an invalid child; DOM elements are not valid children of React components.

Upvotes: 4

Views: 1256

Answers (2)

Nathanael Smith
Nathanael Smith

Reputation: 3311

You should not imperatively modify the DOM with React. Call this.setState and allow React to modify the DOM.

Keep an object representing your comment structure near the top of your component hierarchy, when something change that would need to modify it, you can call this.setState the new/modified comment object.

Upvotes: 1

AJcodez
AJcodez

Reputation: 34206

Instead of thinking about collapsing (v) think about setting the state to collapsed (adj). When the user clicks expand / hide, set a boolean. In your render function, check the boolean.

Something like this:

React.createClass({
  getInitialState: function () {
    return { hidden: false } 
  },

  render: function () {
    return (<div class={ this.state.hidden && 'hidden' } onClick={ this.toggle }>
      { this.props.children }
    </div>)
  },

  toggle: function (ev) {
    this.setState({ hidden: !this.state.hidden })
  },
})

And in the css:

.hidden div { display: none; }

Edit: How to append divs

Stop thinking in verbs. You don't want to append (v) divs, you want divs to either be present (adj) or absent (adj). You can use another boolean, or whatever conditional you'd like:

render: function () {
  return (<div>{ this.state.weWantDivs && this.renderDivs() }</div>)
}

Edit: How to put child view in parent view

Put the child elements in the parent element.

render: function () {
  return <Parent><Child></Child></Parent>
}

And in the parent element render special children property.

var Parent = React.createClass({
  render: function () {
    return <div>{ this.props.children }</div>
  }
})

Upvotes: 3

Related Questions