简体   繁体   中英

Prevent multiple on-click events from firing: ReactJS

I have a situation where in I am having multiple on click events that are fired on a column header. There will be one event for filter dropdown and the other one for sorting. There is a filter icon , on click of which column filter options will be shown. And on click of the header, sorting should also happen.

Now whenever I click on the filter icon, both handlers are getting fired. Can someone help me with this.

On click of filter icon, only filter handler should fire

Help would be appreciated.

Sandbox: https://codesandbox.io/s/relaxed-feather-xrpkp

Parent

import * as React from "react";
import { render } from "react-dom";
import ReactTable from "react-table";
import "./styles.css";
import "react-table/react-table.css";
import Child from "./Child";
interface IState {
  data: {}[];
  columns: {}[];
}

interface IProps {}

export default class App extends React.Component<IProps, IState> {
  constructor(props: any) {
    super(props);
    this.state = {
      data: [
        { firstName: "Jack", status: "Submitted", age: "14" },
        { firstName: "Simon", status: "Pending", age: "15" },
        { firstName: "Pete", status: "Approved", age: "17" }
      ],
      columns: []
    };
  }

  handleColumnFilter = (value: any) => {
    console.log(value);
  };

  sortHandler = () => {
    console.log("sort handler");
  };

  componentDidMount() {
    let columns = [
      {
        Header: () => (
          <div onClick={this.sortHandler}>
            <div style={{ position: "absolute", marginLeft: "10px" }}>
              <Child handleFilter={this.handleColumnFilter} />
            </div>
            <span>First Name</span>
          </div>
        ),
        accessor: "firstName",
        sortable: false,
        show: true,
        displayValue: " First Name"
      },
      {
        Header: () => (
          <div onClick={this.sortHandler}>
            <span>Status</span>
          </div>
        ),
        accessor: "status",
        sortable: false
      }
    ];
    this.setState({ columns });
  }

  render() {
    const { data, columns } = this.state;
    return (
      <div>
        <ReactTable
          data={data}
          columns={columns}
          defaultPageSize={10}
          className="-striped -highlight"
        />
      </div>
    );
  }
}

const rootElement = document.getElementById("root");
render(<App />, rootElement);

Filter Component

import * as React from "react";
import { Icon } from "semantic-ui-react";
import "./styles.css";
interface IProps {
  handleFilter(val1: any): void;
}
interface IState {
  showList: boolean;
}
export default class Child extends React.Component<IProps, IState> {
  constructor(props: any) {
    super(props);
    this.state = {
      showList: false
    };
  }

  toggleList = () => {
    console.log("filter handler");
    this.setState(prevState => ({ showList: !prevState.showList }));
  };

  render() {
    let { showList } = this.state;
    let visibleFlag: string;
    if (showList === true) visibleFlag = "visible";
    else visibleFlag = "";
    return (
      <div>
        <div style={{ position: "absolute" }}>
          <div
            className={"ui scrolling dropdown column-settings " + visibleFlag}
          >
            <Icon className="filter" onClick={this.toggleList} />
          </div>
        </div>
      </div>
    );
  }
}


You just need event.stopPropagation() . This will isolate the event to only this specific execution-block. So now when you click on the filter-icon, it will only trigger the designated event-handler.

  toggleList = (event) => {
    event.stopPropgation()
    console.log("filter handler");
    this.setState(prevState => ({ showList: !prevState.showList }));
  };

You'll also need to use it here as well:

  handleValueChange = (event: React.FormEvent<HTMLInputElement>, data: any) => {
    event.stopPropagation()
    let updated: any;
    if (data.checked) {
      updated = [...this.state.selected, data.name];
    } else {
      updated = this.state.selected.filter(v => v !== data.name);
    }
    this.setState({ selected: updated });
  };

And here:

 passSelectionToParent = (event: any) => {
    event.preventDefault();
    event.stopPropagation()
    this.props.handleFilter(this.props.name, this.state.selected);
  };

Literally, anytime you have a click-event for a parent-markup and it has children mark-up that also have a click-event, you can use event.stopPropagation() to stop the parent click-event from firing.

Here's the sandbox: https://codesandbox.io/s/elated-gauss-wgf3t

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