unsafe_where_true
unsafe_where_true

Reputation: 6300

react: why does the onclick get executed even without having clicked?

Warning: Severe React beginner.

I have a class:

 export default class ItemsView extends React.Component {

    //...

    render() { 
      return (
        <div>
           <Container>
            <Grid container>
              <Grid item xs={4}>
                 <ul style={{listStyleType:"none"}}>
                   {   
                     this.state.items.map((item) => {
                     return <li key={item.number} style={{cursor: "pointer"}}><Item onClick={this.handleSelected(item)} value={item.timestamp}/></li>
                     })  
                   }   
                 </ul>
              </Grid>
              <Grid item xs={4}>
                <ItemDetail item={this.selected} />
              </Grid>
            </Grid>
          </Container>

          </div>
      )
   }
}

handleSelected(item) {
   console.log("handle");
   this.selected = item;
 }

What I want is that when I click on the Item div, which is rendered dynamically as a list of elements, the details of the item would appear in the ItemDetails component.

Apart from the fact that probably my design isn't really "React"y, why does the handleSelected get called when iterating, and not when I click on it?

Upvotes: 4

Views: 664

Answers (3)

John Ruddell
John Ruddell

Reputation: 25842

Aside from the answer Vincenzo posted, you need to also use component state here. A handler that updates a property on the class will not result in a new render cycle. I can see that you are using this.selected in the render as a prop to ItemDetail

<ItemDetail item={this.selected} />

This is problematic as changing the value of this.selected will not trigger a new render. This is a great use case to use component state

export default class ItemsView extends React.Component {
    state = { selected: null, items: [] }
    handleSelected = (selected) => (event) => {
// ----------------------^------------^----
// return a function in the handler to pass a callback to the click handler
      console.log("handle");
      this.setState({ selected });
// -----------^------------^----
// set the selected item on component state when clicked
    }

    //...

    render() { 
      return (
        <div>
           <Container>
            <Grid container>
              <Grid item xs={4}>
                 <ul style={{listStyleType:"none"}}>
                   { this.state.items.map((item) => <li key={item.number} style={{cursor: "pointer"}}>
                       <Item onClick={this.handleSelected(item)} value={item.timestamp}/>
// --------------------------------------------^---------------
// no change necessary here since the handler returns a function.
                     </li>
                   )}   
                 </ul>
              </Grid>
              <Grid item xs={4}>
                <ItemDetail item={this.state.selected} />
// --------------------------------------^---------------
// reference state here
              </Grid>
            </Grid>
          </Container>

          </div>
      )
   }
}

Upvotes: 1

mxdi9i7
mxdi9i7

Reputation: 697

You are mapping over a list of items and want to pass the item to a handler callback (handleSelected in this case). You usually would pass that through by invoking the function with parenthesis (). However, the side effect of this is the function is immediately executed. To fix that you can place it inside an arrow function, allowing it to execute on the click instead.

Hence: onClick={() => this.handleSelected(item)}

Upvotes: 0

Vincenzo Ninni
Vincenzo Ninni

Reputation: 195

You are invoking the function rather than passing a function reference to be executed on click. You should either define the handler to return a function or use a lambda / fat arrow function in the click handler

onClick={() => this.handleSelected(item)}

remember, this.handleSelected is the functions reference. this.handleSelected() is the return value of an already invoked function.

Upvotes: 4

Related Questions