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

时间:2018-10-28 14:43:03

标签: javascript reactjs events event-handling onblur

这些天我在处理一些问题。该问题与使用react冒泡的事件有关。

我实现了带有一些react组件的下拉菜单。这是通过包含ul和一些li元素的div制成的。我需要使下拉菜单可以通过键盘访问,因此我会触发onb​​lur,onfocus,onkeydown和onclick元素以显示和隐藏下拉菜单并与键盘一起使用。

我使用show / hide东西触发props传递给real的函数,当div处于焦点或单击状态时,我显示下拉列表,当onblur时,我将其隐藏以更改组件的状态。问题是我有一些带onclick函数的li元素来选择所需的选项。但是,当我单击某个选项时,将触发父对象的onblur事件,它会更改状态,并且li元素的onclick事件不会触发,因此我无法选择任何选项。

我正在尝试使用事件冒泡或传播来解决此问题,但找不到任何解决方案。请你帮助我好吗?

非常感谢!

编辑:问题代码:

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}
   />
)
};

1 个答案:

答案 0 :(得分:0)

我认为您应该将菜单的状态和事件处理程序提升到父组件,并使子组件变为无状态。因此,当您向孩子触发事件时,会通过道具触发父事件处理程序,因此您现在可以放置一些标志来处理事件(像那样)

父级(onBlur)(在状态上添加标志以检查其是否模糊并且未被单击,反之亦然)

-child(点击)
-child(键盘)。

如果答案不清楚,请ping我。