简体   繁体   中英

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.

I have implemented a drop-down with some react components. This is made with a div containing a ul and some li elements. 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.

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. The problem is that I have some li elements with onclick functions to select the desired option. 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.

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)

-child (click)
-child (keyboard).

please ping me if the answer not clear enough.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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