Javascript 单击React中可单击组件的外部

Javascript 单击React中可单击组件的外部,javascript,reactjs,Javascript,Reactjs,我有一个基本组件,如下所示 class List extends React.Component { constructor() { super(...arguments); this.state = { selected: null, entities: new Map([ [0, { 'name': 'kot'} ], [1, { 'name': 'blini'} ] ]) }; } re

我有一个基本组件,如下所示

class List extends React.Component {
  constructor() {
    super(...arguments);
    this.state = {
      selected: null,
      entities: new Map([
        [0, { 'name': 'kot'} ],
        [1, { 'name': 'blini'} ]
      ])
    };
  }
  render() {
    return (<div>
      <ul>{this.renderItems()}</ul>
    </div>)
  }
  renderItems() {
    return Array.from(this.state.entities.entries()).map(s => {
      const [ id, entry ] = s;
      return <li
        key={id}
        onClick={() => this.setState(state => ({ selected: id }))}
        style={{
          color: id === this.state.selected ? 'red' : 'black'
        }}
      >{entry.name}</li>
    })
  }
}
类列表扩展了React.Component{
构造函数(){
超级(…参数);
此.state={
选中:空,
实体:新地图([
[0,{'name':'kot'}],
[1,{'name':'blini'}]
])
};
}
render(){
返回(
    {this.renderItems()}
) } renderItems(){ 返回Array.from(this.state.entities.entries()).map(s=>{ const[id,entry]=s; 返回
  • this.setState(state=>({selected:id}))} 风格={{ 颜色:id==this.state.selected?'red':'black' }} >{entry.name}
  • }) } }
    这样做的目的是允许我单击任何元素并选择它。选定的元素将显示为红色

    但是,如果发现不是这些元素之一的单击事件,我希望该行为将取消设置任何当前选定的项目


    如何在React中实现这一点?

    列表中,您可以添加

      componentDidMount() {
        window.addEventListener("click", (e) => {
          let withinListItems = ReactDOM.findDOMNode(this).contains(e.target);
          if ( ! withinListItems ) {
            this.setState({ selected: null });  
          }
        });
      }
    
    在您的
    渲染图中,将
    onClick
    更改为

    onClick={ (e) => {
        // e.stopPropagation();
        this.setState({ selected: id });
      }
    }
    
    你可以签出这个代码笔

    编辑:
    @kubajz所说的是真的,因此我更新了答案。

    在您的
    列表
    组件中,您可以添加

      componentDidMount() {
        window.addEventListener("click", (e) => {
          let withinListItems = ReactDOM.findDOMNode(this).contains(e.target);
          if ( ! withinListItems ) {
            this.setState({ selected: null });  
          }
        });
      }
    
    在您的
    渲染图中,将
    onClick
    更改为

    onClick={ (e) => {
        // e.stopPropagation();
        this.setState({ selected: id });
      }
    }
    
    你可以签出这个代码笔

    编辑:
    @kubajz所说的是真的,因此我更新了答案。

    随机用户的答案是正确的,它可能有一个缺陷-它依赖于
    stopPropagation
    ,并且有可能某些代码不再按预期工作-想象一下在页面上收集用户行为并将度量发送到某处-stopPropagation将防止冒泡,因此不会记录单击。另一种方法是检查在
    事件中单击的内容。目标


    还有一个很好的实用程序组件,用于在文档级别进行侦听:

    随机用户的答案是正确的,它可能有一个缺陷-它依赖于
    stopPropagation
    ,并且有可能某些代码不再按预期工作-想象一下在页面上收集用户行为并将度量发送到某处-stopPropagation将防止冒泡,因此不会记录单击。另一种方法是检查在
    事件中单击的内容。目标


    还有一个很好的实用程序组件,用于在文档级别进行侦听:

    使列表项成为一个单独的组件,如
    。您的父
    列表
    组件应具有宽度和高度,以占用更多空间并实现其自己的onClick事件。将列表项设置为一个独立的组件,如
    。您的父
    列表
    组件应具有宽度和高度,以占用更多空间并实现其自己的onClick事件。这不会在卸载组件时删除事件侦听器。(事实上,它无法删除事件侦听器;因为它使用一个匿名本地函数来
    addEventListener
    ,所以无法检索它来调用
    removeEventListener
    )您应该将事件处理程序放在类方法中(例如,
    handleWindowClick
    ),将其绑定到构造函数中(
    this.handleindowclick=handleindowclick.bind(this)
    ),并添加删除事件的
    componentWillUnmount
    方法(
    window.removeEventListener(“单击”,this.handleindowclick)
    )。此外,如果父div在作用域内,它将失败。当卸载组件时,它不会删除事件侦听器。(事实上,它无法删除事件侦听器;因为它使用匿名本地函数来
    addEventListener
    ,因此无法检索它以调用
    removeEventListener
    )您应该将事件处理程序放在类方法中(例如,
    handleindowclick
    ),将其绑定到构造函数中(
    this.handleindowclick=handleindowclick.bind(this)
    ),并添加一个删除事件的
    componentWillUnmount
    方法(
    window.removeEventListener(“单击”,this.handleindowclick)
    )。此外,如果父div在范围内,则它将失败