在 React 中单击组件外部时更改状态

Posted

技术标签:

【中文标题】在 React 中单击组件外部时更改状态【英文标题】:Change the state when clicking outside a component in React 【发布时间】:2018-07-18 08:37:42 【问题描述】:

我有一个下拉菜单,如下图所示:

当我单击文件夹图标时,它会打开和关闭,因为 showingProjectSelector 属性处于设置为 false 的状态。

  constructor (props) 
    super(props)
    const  organization, owner, ownerAvatar  = props
    this.state = 
      owner,
      ownerAvatar,
      showingProjectSelector: false
    
  

当我单击该图标时,它会正确打开和关闭。

<i
  onClick=() => this.setState( showingProjectSelector: !this.state.showingProjectSelector )
  className='fa fa-folder-open'>
</i>

但是我想要做的是在我点击下拉菜单时关闭它。我如何在不使用任何库的情况下做到这一点?

这是整个组件:https://jsbin.com/cunakejufa/edit?js,output

【问题讨论】:

***.com/questions/32553158/… github.com/Pomax/react-onclickoutside 我已经在多个项目中使用过这个包,它可以完美运行:npmjs.com/package/react-onclickoutside 希望这能帮助stackblitz.com/edit/react-vzhmj7我为弹出框做的,在你的场景中像这样使用 【参考方案1】:

您可以尝试利用 onBlur:

<i onClick=... onBlur=() => this.setState(showingProjectSelector: false)/>

【讨论】:

感谢您的回答!它没有工作,我不知道为什么:(【参考方案2】:

我遇到了同样的问题。阅读后解决: Detect click outside React component 请尝试:

【讨论】:

【参考方案3】:

您应该使用高阶组件来包装您想要在其外部监听点击的组件。

这个组件示例只有一个 prop:“onClickedOutside”,它接收一个函数。

ClickedOutside.js
import React,  Component  from "react";

export default class ClickedOutside extends Component 
  componentDidMount() 
    document.addEventListener("mousedown", this.handleClickOutside);
  

  componentWillUnmount() 
    document.removeEventListener("mousedown", this.handleClickOutside);
  

  handleClickOutside = event => 
    // IF exists the Ref of the wrapped component AND his dom children doesnt have the clicked component 
    if (this.wrapperRef && !this.wrapperRef.contains(event.target)) 
      // A props callback for the ClikedClickedOutside
      this.props.onClickedOutside();
    
  ;

  render() 
    // In this piece of code I'm trying to get to the first not functional component
    // Because it wouldn't work if use a functional component (like <Fade/> from react-reveal)
    let firstNotFunctionalComponent = this.props.children;
    while (typeof firstNotFunctionalComponent.type === "function") 
      firstNotFunctionalComponent = firstNotFunctionalComponent.props.children;
    

    // Here I'm cloning the element because I have to pass a new prop, the "reference" 
    const children = React.cloneElement(firstNotFunctionalComponent, 
      ref: node => 
        this.wrapperRef = node;
      ,
      // Keeping all the old props with the new element
      ...firstNotFunctionalComponent.props
    );

    return <React.Fragment>children</React.Fragment>;
  

【讨论】:

【参考方案4】:

如果你想使用一个已经存在的小组件(466 字节压缩)来实现这个功能,那么你可以查看这个库react-outclick。

该库的好处在于它还可以让您检测组件外部和另一个组件内部的点击。它还支持检测其他类型的事件。

使用该库,您可以在组件中拥有类似的内容。

import OnOutsiceClick from 'react-outclick';

class MyComp extends Component  

  render() 
    return (
      <OnOutsiceClick
        onOutsideClick=() => this.setState(showingProjectSelector: false)>
        <Dropdown />
      </OnOutsiceClick>
    );
  

【讨论】:

【参考方案5】:

包装组件 - 即包装所有其他组件的组件

创建运行函数 handleClick 的 onClick 事件。

handleClick 函数检查点击事件的 ID。

当 ID 匹配时,它会做一些事情,否则它会做其他事情。

const handleClick = (e) => 

    if(e.target.id === 'selectTypeDropDown')
        setShowDropDown(true)
     else 
        setShowDropDown(false); 
    



所以我有一个下拉菜单,只有当你点击下拉菜单时才会出现,否则它会隐藏它。

【讨论】:

以上是关于在 React 中单击组件外部时更改状态的主要内容,如果未能解决你的问题,请参考以下文章

为啥组件在单击和状态更改时会重新渲染?

React - 从另一个子组件更改子组件中的状态

React - 单击位于组件外部的按钮时重新渲染组件

React 功能组件中状态更改后组件未重新渲染

React 组件不会在值更改时重新渲染并显示 CSS 更改

更改数组中的一个状态会导致在 React Hooks 中重新渲染整个循环生成的自定义组件