dwjohnston
dwjohnston

Reputation: 11900

Referencing state for loop rendered elements in react

See my code pen here:

https://codepen.io/kiwideejay/pen/zEyZdj?editors=1111

The key line is here:

  componentWillMount() {        

        let items = this.props.objs.map((v,i) =>{       
            return <li 
                      className = {(this.state.i === i) ? "selected" : ""} > 
                         {v} - {this.state.i} - {i}
                   </li> 
        }); 

        this.setState({items:items});
      }

It's pretty straight forward - I want to conditionally set the class of each of the elements, depending on the value of this.state.i. However - I'm guessing the way I've generated these dom elements isn't react responsive.

What's the correct way to do this?

Upvotes: 0

Views: 199

Answers (3)

bennygenel
bennygenel

Reputation: 24680

Setting state in componentWillMount is not a good practice like it states in react docs..

componentWillMount() is invoked immediately before mounting occurs. It is called before render(), therefore setting state synchronously in this method will not trigger a re-rendering. Avoid introducing any side-effects or subscriptions in this method.

Rather then setting the items to state and then rendering you can just map in render function or you can separate the function and just call it in render. If you still would like to have the items in state you should use componentDidMount life-cycle method.

The way you set the className is just fine if you ask me.

Example

renderListItems = () => {
  return this.props.objs.map((v,i) => {       
           return ( 
             <li className={(this.state.i === i) ? "selected" : ""}> 
               {`${v} - ${this.state.i} - ${i}`}
             </li>
           ) 
         }); 
}

render() {
  return(
    <div>
      <ul>
        {this.renderListItems()}
      </ul>
    <div>
  )
}

Upvotes: 1

dwjohnston
dwjohnston

Reputation: 11900

Turns out you don't need to set the items to variable before the render function. Just render them in the render() method's return statement.

  render() {                
    return <div>

      <ul> 
        {this.props.objs.map((v,i) =>{       
              return <li 
                           className = {(this.state.i === i) ? "selected" : ""} > 
                                  {v} - {this.state.i} - {i} 
                     </li> 
        })}
      </ul>

     //snip

Codepen here: https://codepen.io/kiwideejay/pen/boOqQg?editors=1111

Upvotes: 0

Huy
Huy

Reputation: 11206

You want to use componentWillUpdate() instead of componentWillMount(). componentWillMount() is a callback that only gets called once before render() so setting the state in this method will not trigger a re-render.

Upvotes: 1

Related Questions