【问题标题】:Change the state when clicking outside a component in React在 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
【问题讨论】:
标签:
javascript
reactjs
components
【解决方案1】:
您可以尝试利用 onBlur:
<i onClick={...} onBlur={() => this.setState({showingProjectSelector: false})}/>
【解决方案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);
}
}
所以我有一个下拉菜单,只有当你点击下拉菜单时才会出现,否则它会隐藏它。