【问题标题】:Material UI | React | OnClick Event always sends the last index材质界面 |反应 | OnClick 事件总是发送最后一个索引
【发布时间】:2019-09-03 13:04:56
【问题描述】:

我无法正确选择列表项

我是 React 的初学者,我在迭代 Material UI 中的 List Item 时遇到了麻烦。我正在遍历 json 数组并将列表项添加到列表中。 点击任何列表项时,列表总是选择最后一项

 function handleListItemClick(index) {
    setSelectedIndex(index);

    props.user.updateState(index);
    props.user.setCourseName(props.mycourses[index].courseName);
  }

  function RenderListItem(props) {
    var indents = [];
    let ind = 0;

    for (var key in props.coursevals) {
      indents.push(
        // <span>

        <ListItem
          button
          selected={selectedIndex === key}
          onClick={() => handleListItemClick(key)}
          // onClick={event => handleListItemClick(event, 0)}
          className={classes.ListItem}
          key={key}
        >
          {/* {console.log(key)} */}
          <ListItemIcon>
            <img
              className={classes.courseimg}
              src="../../../public/images/book.png"
            />
          </ListItemIcon>
          <ListItemText primary={props.coursevals[key].courseId} />
          <img
            className={classes.rightarrow}
            src="../../../public/images/rightarrow.png"
          />
        </ListItem>
      );
    }
    return indents;



 }

OnClick 事件总是将最后一个索引发送给函数。我想发送我刚刚点击的索引

【问题讨论】:

    标签: javascript arrays reactjs list listview


    【解决方案1】:

    问题在于变量key 在每次迭代中都是相同的(它将在每次循环开始时使用新键进行更新)。您正在传递一个回调,该回调具有对该变量的引用,该变量在迭代结束时将具有最后一个键的值。

    我无法测试以下代码,但它应该可以工作。请告诉我。这个想法是为每个循环保留对“当前键”的引用,因此每个回调都会引用正确的值。

    请注意,为了更加一致,我已经替换了 for 正文中的所有 key 外观。实时(不是在回调时)计算的表达式显然没有这个问题。

    另一种更奇特的方式是使用Function.prototype.bind()(参见MDN)。 onClick={handleListItemClick.bind(undefined, key)}。它将传递一个嵌入了key 作为第一个参数的函数。

    最后一种选择,使用forEach() 代替 for 循环会起作用,因为每次迭代都会创建一个新的index。 (结果与下面的代码相同)。

     function handleListItemClick(index) {
        setSelectedIndex(index);
    
        props.user.updateState(index);
        props.user.setCourseName(props.mycourses[index].courseName);
      }
    
      function RenderListItem(props) {
        var indents = [];
        let ind = 0;
    
        for (var key in props.coursevals) {
          let currentKey = key;
          indents.push(
            // <span>
    
            <ListItem
              button
              selected={selectedIndex === currentKey}
              onClick={() => handleListItemClick(currentKey)}
              className={classes.ListItem}
              key={currentKey}
            >
              {/* {console.log(currentKey)} */}
              <ListItemIcon>
                <img
                  className={classes.courseimg}
                  src="../../../public/images/book.png"
                />
              </ListItemIcon>
              <ListItemText primary={props.coursevals[currentKey].courseId} />
              <img
                className={classes.rightarrow}
                src="../../../public/images/rightarrow.png"
              />
            </ListItem>
          );
        }
        return indents;
    
    
    
     }
    
    

    【讨论】:

    • @MuhammadZulqarnainSabir 太棒了!有关更多信息,请参阅我的 las 编辑。
    【解决方案2】:

    我认为您忘记将事件作为第一个参数传递

    onClick={(event) => handleListItemClick(event, key)}
    

    你的handleListItemClick 函数应该声明为

    function handleListItemClick(event, index) {
        event.preventDefault()
        ...
    }
    

    【讨论】:

    • 仍然得到相同的结果,我在数组中有两个项目,单击项目 0 时,函数会在控制台上打印索引 1
    • 我会使用 array.map 函数,因为您的键似乎有问题 for (var key in props.coursevals) { 变为 `` props.coursevals.map((value, index) => { ... 你的代码在这里 ... }) ```
    【解决方案3】:

    你能用 map 代替 for 循环吗?所以你的代码应该如下所示。

    props.coursevals.map((courseval, index) => {
      indents.push(
        <ListItem
          key={index}
          button
          selected={selectedIndex === index}
          onClick={() => handleListItemClick(index)}
          className={classes.ListItem}
        >
          <ListItemIcon>
            <img
              className={classes.courseimg}
              src="../../../public/images/book.png"
            />
          </ListItemIcon>
          <ListItemText primary={courseval.courseId} />
          <img
            className={classes.rightarrow}
            src="../../../public/images/rightarrow.png"
          />
        </ListItem>
      );
    });
    

    希望对您有所帮助!

    【讨论】:

    • 您能否将答案标记为已接受并为该答案投票?所以这对其他开发者也有帮助。
    【解决方案4】:

    它与 React 无关,而与 Javascript 本身有关。在带有回调函数的for 循环中使用var 时要小心。所有这些函数都指向同一个值,即迭代结束时的最后一个索引。尝试使用let 而不是var 甚至更好:根本不要使用for 循环:

    const indents = Object.keys(props.coursevals).map(key => (
      <ListItem
          key={index}
          button
          selected={selectedIndex === index}
          onClick={() => handleListItemClick(index)}
          className={classes.ListItem}
        >
        ...
    

    你可以参考这个问题:JavaScript closure inside loops – simple practical example

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-07-06
      • 2014-11-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-05
      相关资源
      最近更新 更多