【问题标题】:Get a reference to clicked item with MaterialUI and React使用 MaterialUI 和 React 获取对单击项目的引用
【发布时间】:2018-05-16 09:42:28
【问题描述】:

我在反应组件中有这个简单的代码:

render(){
    return(
        <List>
            <MenuItem onClick={this.onItemClick} key={1}>Menu item 1</MenuItem>
            <MenuItem onClick={this.onItemClick} key={2}>Menu item 2</MenuItem>
            <MenuItem onClick={this.onItemClick} key={3}>Menu item 3</MenuItem>
        </List>
    )
}

onItemClick = (event) => {
    console.log(event, event.target, event.target.key); //???
}

当我单击一个列表项时,我想检索它的引用以分配该项目的selected 属性。 event.target 给出了一个&lt;li&gt; 对象而不是&lt;MenuItem&gt; 对象,所以event.target.key 返回undefined

不幸的是,material-ui docs 没有给出任何关于如何处理事件的解释。

我做错了什么?

【问题讨论】:

  • 我使用MenuItem 而不是ListItem 来获取selected 属性。见this issue
  • 它在文档中定义!如果您想查看示例,您需要进入Demo 部分。请参阅以下链接:material-ui-next.com/demos/menus
  • 谢谢山姆,我错过了!

标签: reactjs material-ui


【解决方案1】:

为了得到点击的Item,你可以使用箭头函数或者在render中绑定,这不是最正确的方法

<MenuItem onClick={() => this.onItemClick(1)} key={1}>Menu item 1</MenuItem>

或者在 MenuItemClick 周围写一个包装器

class ExtendedMenuItem extends React.Component {
   onClick=() => {
        this.props.onClick(this.props.id);
   }
   render(){
      const {id, children, ...others} = this.props;
      return <MenuItem onClick={this.onClick} key={id} {...others}>children</MenuItem>
   }
}

然后像这样使用它

<ExtendedMenuItem onClick={this.onItemClick} id={1}>Menu item 1</ExtendedMenuItem >

【讨论】:

  • 确实,这行得通。谢谢!但这是否意味着 - 要使用正确的方法 - 我应该始终使用包装器方法?为什么箭头函数方法不对?
  • 使用箭头函数在每次渲染上创建一个新函数,检查stackoverflow.com/questions/45053622/…
  • 确实有道理。因此,我的结论是仅在组件大量更新的情况下使用包装器解决方案。也许 material-ui 的人应该在组件中添加一些内置的事件处理程序,例如 &lt;List&gt;&lt;Menu&gt; 来处理这些包装器
【解决方案2】:

event.target 给出了一个li 元素,因为浏览器使用的是 DOM,而不是 React 保存在内存中的虚拟结构。

呈现的页面上没有MenuItem 元素。取而代之的是由MenuItems 渲染的元素

点击事件来自实际的 DOM 元素,例如 div、input、li。为什么不来自 MenuItem?因为页面上没有&lt;MenuItem&gt;。当你点击元素时,你点击的是&lt;li&gt;s,而不是&lt;MenuItem&gt;s。

您想要做的可以通过在 virtual &lt;MenuItem&gt; 上设置一个“虚构的”点击处理程序来实现:

<VirtualElement onClick={virtualClickHandler} />

然后,在渲染 real DOM 元素 &lt;li&gt; 时,VirtualElement 会在其上设置一个 real 点击处理程序:

class VirtualElement {
    realClickHandler (e) { // Let's assume you've bound this in the constructor
        // do stuff with "e" and "this.props"
    }
    render () {
        return <li onClick={realClickHandler} />
    }
}

现在,realClickHandler 的范围包含 thise。这意味着,它可以读取 VirtualElements event 对象的状态和(虚拟)道具。

最后一部分 - 唯一剩下的是virtualClickHandler。它住在哪里?在this.props。因为之前你说&lt;VirtualElement onClick={virtualClickHandler} /&gt;,这个onClick 处理程序被写入VirtualElement 的props 对象。

您要做的是从 realClickHandler 调用 virtualClickHandler,它会同时看到 eventthis em> 对象:

realClickHandler (e) {
    // Here you can tell the virtualClickHandler whatever it needs to know:
    this.props.onClick({
        event: e,
        key: this.props.key
    });
}

【讨论】:

  • 感谢您的解释。我曾经使用另一个内置了事件处理程序的 UI 库。Material-ui 没有,所以这是我的错误
【解决方案3】:

你可以这样做:

render(){
    return(
        <List>
            <MenuItem onClick={this.onItemClick(1)} key={1}>Menu item 1</MenuItem>
            <MenuItem onClick={this.onItemClick(2)} key={2}>Menu item 2</MenuItem>
            <MenuItem onClick={this.onItemClick(3)} key={3}>Menu item 3</MenuItem>
        </List>
    )
}

onItemClick = itemId=>(event) => {
    console.log(itemId,event, event.target, event.target.key); //???
}

【讨论】:

  • 确实,这是不正确的,因为onItemClick 函数将在渲染期间执行。相反,() =&gt; this.onItemClick(1) 确实有效(就像 Khatri 提到的那样)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-07-28
  • 2020-11-17
  • 2020-03-24
  • 2018-11-17
  • 2011-03-02
  • 2021-11-10
  • 1970-01-01
相关资源
最近更新 更多