简体   繁体   English

具有setState的Onblur事件不允许React中子级的onClick

[英]Onblur event with setState doesn't allow onClick of child in React

I was dealing with some problem these days ago. 这些天来我正在处理一些问题。 The problem is related with event bubbling with react. 该问题与使用react冒泡的事件有关。

I have implemented a drop-down with some react components. 我已经实现了一些反应组件的下拉菜单。 This is made with a div containing a ul and some li elements. 这是通过包含ul和一些li元素的div制成的。 I need to make the drop down accessible by keyboard so I fire the onblur, onfocus, onkeydown and onclick elements to show and hide the drop down and to use it with keyboard. 我需要使下拉菜单可以通过键盘访问,所以我触发了onblur,onfocus,onkeydown和onclick元素以显示和隐藏下拉菜单并与键盘一起使用。

I fire a function passed by props to real with the show/hide stuff and when the div is focused or clicked I show the drop down and when is onblur I hide it changing the state of the component. 我用show / hide东西触发props传递给real的函数,当div处于焦点或单击状态时,我显示下拉列表,当onblur时,我隐藏它以更改组件的状态。 The problem is that I have some li elements with onclick functions to select the desired option. 问题是我有一些带onclick函数的li元素来选择所需的选项。 However, when I click on an option, onblur event of parent fires, it changes the state and onclick event of the li element doesn't fire so I cannot choose any option. 但是,当我单击一个选项时,将触发父对象的onblur事件,它会更改状态,并且li元素的onclick事件不会触发,因此我无法选择任何选项。

I'm trying to solve this using event bubbling or propagation but I couldn't find any solution. 我正在尝试使用事件冒泡或传播来解决此问题,但找不到任何解决方案。 Could you please help me? 请你帮助我好吗?

Thanks a lot! 非常感谢!

EDIT: Code of the problem: 编辑:问题的代码:

const Filter = (props: FilterProps) => {
...
<div onBlur={(e) =>
   {props.handleDropdown(e, props.isOpen)}} onKeyDown={(e) => {props.handleKeyDown(e)}} onFocus={(e) => props.handleDropdown(e, props.isOpen)} className={props.isOpen ? "Dropdown Dropdown--multiselection is-open" : "Dropdown Dropdown--multiselection"}>
   <Button className="FilterField Dropdown__trigger Button--secondary" onClick={(e) => props.handleDropdown(e, props.isOpen)}>
   <span className="Dropdown__label">{setLabels(ASSETS, props.selectedAssets)}</span>
   <span className="Dropdown__caret"></span>
   </Button>
   <ul className="Dropdown__menu">
      <li className={checkSelectedAsset(-1, props.selectedAssets).class} onClick={(e) => props.selectAsset(e, -1)}>
      <Translate id="all"/>
      {checkSelectedAsset(-1, props.selectedAssets).isSelected && 
      <span className="Dropdown__menu-item-icon">
         <IconCheck/>
      </span>
      }
      </li>
      <li className="Dropdown__menu-divider"></li>
      {
      (props.assetClasses && props.assetClasses.length > 0) &&
      props.assetClasses.map((asset) => {
      return (
      <li className={checkSelectedAsset(asset, props.selectedAssets).class} onClick={(e) => props.selectAsset(e, asset)}>
      {
      <span>
         <Translate id={`products.${Helper.getType(asset)}`}/>
      </span>
      }{checkSelectedAsset(asset, props.selectedAssets).isSelected && 
      <span className="Dropdown__menu-item-icon">
         <IconCheck/>
      </span>
      }
      </li>
      );
      })
      }
   </ul>
</div>

interface PositionsContainerState {
...
isOpen: boolean;
}   

class Container extends 
React.Component<ContainerProps, ContainerState> {
openCloseDropdown = (event, isOpen: boolean) => {
event.stopPropagation();
if (event.type === "focus") {
this.setState({
dropdownExpanded: true,
focusTriggered: true
});
}
else if (event.type === "blur") {
this.setState({
dropdownExpanded: false,
focusTriggered: false
});
}
else if (event.type === "click") {
if (this.state.focusTriggered) {
this.setState({
dropdownExpanded: isOpen,
focusTriggered: false
});
} 
else {
this.setState({
dropdownExpanded: !isOpen,
});
}
}
};
selectAsset = (event, asset: number) => {
//event.detail.keyboardEvent.preventDefault();
if (asset < 0) {
this.props.dispatch(setFilterAssets([]));
}
else {
let auxSelectedAssets = assign([], this.props.selectedAssets);
if (auxSelectedAssets.indexOf(asset) === -1)
auxSelectedAssets.push(asset);
else
auxSelectedAssets.splice(auxSelectedAssets.indexOf(asset), 1);
this.props.dispatch(setFilterAssets(auxSelectedAssets));
}
}
render() {
return (
<Filter
   handleDropdown={props.openCloseDropdown}
   isOpen={props.isOpen}
   selectAsset={props.selectAsset}
   />
)
};

I think u should lift the state and event handlers of the menu up to the parent component and make the child ones stateless. 我认为您应该将菜单的状态和事件处理程序提升到父组件,并使子组件变为无状态。 so when u fire an event on the child to will trigger the handler on the parent through the prop so now you can put some flags to handle the events (like that) 因此,当您向孩子触发事件时,将通过道具触发父事件处理程序,因此您现在可以放置一些标志来处理事件(像这样)

parent (onBlur) (add flag on the state to check if it's blur and not clicked and vice-versa) parent(onBlur)(在状态上添加标志以检查其是否模糊并且未被单击,反之亦然)

-child (click) -child(单击)
-child (keyboard). -child(键盘)。

please ping me if the answer not clear enough. 如果答案不清楚,请ping我。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM