0

I am making a react list, whose items should trigger an action to update state. Both the triggering and the state update occur, however, the onClick method is calling the action with the same argument every time. This should not occur. The argument passed to the action must depend on the item of the list clicked.

I can not seam to find the bug that is causing this error.

This is my dropdown class, where the list is rendered.

class DropDownMenu extends React.Component {
  constructor(props){
    super(props)
  }
  render(){
    let content = []
    var categories = this.props.categories
    for (var i=0; i < categories.length; i++) {
      var catName = categories[i]
      var line = (
        <li
          key ={i}
          onClick = {() => {this.props.onClick(catName)}}
        >
        <p>{catName}</p>
        </li>
      )
      content.push(line)
    }
    return (
      <div>
        <Dropdown ref="dropdown">
          <DropdownTrigger>Categories</DropdownTrigger>
          <DropdownContent>
            <ul>
              { content }
            </ul>
          </DropdownContent>
        </Dropdown>
      </div>
    )
  }
}

This is the container that manages the state and calls the above class

class MenuContainer extends React.Component {
  constructor(props) {
    super(props)
  }

  render(){
    return (
      <div>
        <div>
          <a onClick = {() => {this.props.changeView("main")}}>back</a>
          <a onClick = {() => {this.props.changeView("shoppingCart ")}}>my cart</a>
        </div>
        <div>
          <DropDownMenu
            categories = {this.props.categories}
            onClick = {(catName) => {this.props.selectCategory(catName)}}
          />
          <ItemList
            items = {this.props.items}
          />
        </div>
      </div>
    )
  }
}

const mapStateToProps = (state) => {
  return {
    categories: getCategories(state),
    items: getItems(state)
  }
}

const mapDispathToProps = (dispatch) => {
  return {
    changeView: (view) => {
      dispatch(setView(view))
    },
    selectCategory: (catName) => {
      dispatch(setCategory(catName))
    }
  }
}

export default connect(mapStateToProps, mapDispathToProps)(MenuContainer)

I reducer the error to the line:

   for (var i=0; i < categories.length; i++) {
      var catName = categories[i]
      var line = (
        <li
          key ={i}
          onClick = {() => {this.props.onClick(catName)}}
        >
        <p>{catName}</p>

I replaced this.props.onClick with console log of the catName, and it always logs the same, althoug it correctly shows the items in the

tag.

1 Answer 1

7

Your for loop does not form a closure. Better use a map function like this

let content = categories.map((catName, i) => {
      return (
        <li
          key ={i}
          onClick = {() => {this.props.onClick(catName)}}
        >
        <p>{catName}</p>
        </li>
      )
    });
Sign up to request clarification or add additional context in comments.

5 Comments

That worked perfectly, thank you. just a follow up question, how can i pass a unique ID to the <li> tag, since the {i} from the for function is gone.
Map still provides the index as the second argument in your function. although using the index as a key is usually a bad idea.
@RafaelMarques No its not gone. Second argument of map calback is index. Check updated answer
perfect, thank you. will mark this as answered in 4 minutes (allowed time)
Just a quick comment: Using the index as a key isn't always a bad idea. If the items in the list are guaranteed to not change their order, then using the index is fine. Otherwise, you will want to use a unique identifier for each record being mapped.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.