javascript - react : Warning: Can't perform a React state update on an unmounted component

标签 javascript reactjs redux react-redux react-router

我在此文件中使用 Redux,但是当我单击第二个组件时出现此错误。

Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.

它特定于此文件,我在下面分享了它的代码。

import React, { Component } from "react";
import { CSVLink } from "react-csv";
import moment from "moment";
import { connect } from "react-redux";
import axios from "axios";
import { fetchAllCustomerData } from "../../actions/customer";
import SaleTables from "./SaleTables";
import { DateRangePicker } from "react-dates";
import "react-dates/initialize";
import "react-dates/lib/css/_datepicker.css";
import Pagination from "rc-pagination";
import "rc-pagination/assets/index.css";
import Loader from "react-loader-spinner";
import "./style.css";
import { Tooltip } from "reactstrap";

class CustomerReport extends Component {
  constructor(props) {
    super(props);
    this.state = {
      loading: true,
      pageNumber: 1,
      bySearch: "",
      cityName: "",
      tooltipOpen: false,
      branches: [],
      branchLoad: false,
      agentShow: false,
      dateShow: true,
      agents: [],
      status: "fetchAll",
      url: "/api/customer/all?limit=10",
      branchValue: "",
      searchInput: "",
      csvData: [],
      focusedInput: null,
      sureDate: false
    };
  }

  headers = [
    {
      label: "id",
      key: "id"
    },
    {
      label: "Name",
      key: "firstName"
    },
    {
      label: "Phone",
      key: "contact1"
    },
    {
      label: "Email",
      key: "email"
    },
    {
      label: "CNIC",
      key: "cnic"
    },
    {
      label: "Created",
      key: "createdAt"
    },
    {
      label: "Created by Agent",
      key: "byAgent"
    }
  ];

  componentDidMount() {
    this.fetchAllCustomerData();
    document.title = "Customer Report";
    this.getAllCustomer();
  }

  getAllCustomer = () => {
    axios.get("/api/customer/all").then(res => {
      this.setState({
        csvData: res.data.rows
      });
    });
  };

  fetchAllCustomerData = (pageNumber = 1) => {
    this.setState({
      pageNumber
    });
    const { url } = this.state;
    this.props.fetchCustomers(pageNumber, url);
  };

  handleSearchBy = e => {
    const { value } = e.target;
    this.setState({
      bySearch: value
    });
  };

  handleCity = e => {
    const { value } = e.target;
    axios.get(`/api/officeBranch/?searchBy=city&q=${value}`).then(res => {
      this.setState({
        branches: res.data.rows,
        branchLoad: true,
        url: this.state.url
      });
    });
  };

  handleChange = e => {
    this.setState({
      searchInput: e.target.value
    });
  };

  submitHandle = (e, pageNumber = 1) => {
    e.preventDefault();
    const url = `/api/customer/all?searchBy=id&offset=0&limit=10&q=${this.state.searchInput}`;
    this.setState({
      url
    });
    this.props.fetchCustomers(pageNumber, url);
  };

  fetchAgents = (e, pageNumber = 1) => {
    const { value } = e.target;
    let split = value.split(",");
    let url = `/api/customer/all?searchBy=branch&q=${split[1]}&limit=10`;
    this.setState({
      url,
      pageNumber: 1
    });

    axios
      .get(`/api/officebranch/branchAgents?officeBranchId=${value}`)
      .then(res => {
        this.setState({
          agents: res.data.rows,
          agentShow: true
        });
      });

    this.props.fetchCustomers(pageNumber, url);
  };

  toggle = () => {
    this.setState({
      tooltipOpen: !this.state.tooltipOpen
    });
  };

  loadAgents = (e, pageNumber = 1) => {
    const { value } = e.target;
    const url = `/api/customer/all?searchBy=agent&q=${value}&limit=10`;
    this.setState({
      url,
      pageNumber: 1
    });
    this.props.fetchCustomers(pageNumber, url);
  };

  handleDatesChange = (startDate, endDate, pageNumber = 1) => {
    if (startDate !== "" && endDate !== "") {
      let url = `/api/customer/all?fromDate=${startDate.format(
        "YYYY-MM-DD"
      )}&toDate=${endDate.format("YYYY-MM-DD")}`;
      this.setState({
        url,
        sureDate: true,
        pageNumber: 1,
        startDate: startDate,
        endDate: endDate
      });

      this.props.fetchCustomers(pageNumber, url);
    }
  };

  render() {
    const { customer_users, isLoading, status, cities } = this.props;
    const {
      bySearch,
      branchLoad,
      branches,
      agentShow,
      agents,
      startDate,
      endDate,
      sureDate
    } = this.state;
    let csvCustomerData = this.state.csvData.map(row => ({
      ...row,
      firstName: row.firstName + " " + row.lastName,
      createdAt: moment(row.createdAt).format("YYYY-MM-DD"),
      byAgent: row.user.firstName + " " + row.user.lastName,
      cnic: `=""${row.cnic}""`
    }));

    let csvFilterCustomerData =
      customer_users &&
      customer_users.data.rows.map(row => ({
        ...row,
        firstName: row.firstName + " " + row.lastName,
        createdAt: moment(row.createdAt).format("YYYY-MM-DD"),
        byAgent: row.user.firstName + " " + row.user.lastName,
        cnic: `=""${row.cnic}""`
      }));

    return (
      <div>
        {customer_users && customer_users.data.rows ? (
          <div className="pillsWrap">
            {/* Filters HTML */}
            <div className="filtersMain">
              <div className="row">
                <div className="col-md-12">
                  <div className="row">
                    <div className="col-md-2">
                      <div className="officeFilter">
                        <select
                          className="browser-default custom-select marginArea"
                          onChange={this.handleSearchBy}
                        >
                          <option> By </option>
                          <option value="id"> Id </option>
                          <option value="agent"> Agent </option>
                        </select>
                      </div>
                    </div>

                    {bySearch === "id" ? (
                      <div className="col-md-6">
                        <form onSubmit={this.submitHandle}>
                          <input
                            type="text"
                            name="search"
                            placeholder="Search.."
                            className="searchBox"
                            onChange={this.handleChange}
                            autoComplete="off"
                          />
                        </form>
                      </div>
                    ) : null}

                    {bySearch === "id" || bySearch === "agent" ? null : (
                      <div className="col-md-10 pull-right">
                        <div className="dateFilter">
                          <DateRangePicker
                            startDate={moment(startDate)}
                            endDate={moment(endDate)}
                            onDatesChange={dateData => {
                              this.handleDatesChange(
                                dateData.startDate,
                                dateData.endDate
                              );
                            }}
                            focusedInput={this.state.focusedInput}
                            onFocusChange={focusedInput =>
                              this.setState({ focusedInput })
                            }
                            startDateId="TASKS_FILTER_START_DATE_UNIQUE_ID"
                            endDateId="TASKS_FILTER_END_DATE_UNIQUE_ID"
                            numberOfMonths={1}
                            isOutsideRange={day => false}
                            displayFormat="MMM DD / YY"
                          />
                        </div>
                      </div>
                    )}

                    {bySearch === "agent" ? (
                      <div className="col-md-2">
                        <select
                          className="browser-default custom-select marginArea"
                          onChange={this.handleCity}
                        >
                          <option>By City</option>
                          {cities.data.map(item => (
                            <option value={item.name} key={item.id}>
                              {item.name}
                            </option>
                          ))}
                        </select>
                      </div>
                    ) : null}

                    {bySearch === "agent" && branchLoad ? (
                      <div className="col-md-2">
                        <select
                          className="browser-default custom-select marginArea"
                          onChange={this.fetchAgents}
                        >
                          <option>By Branch</option>
                          {branches.map(item => (
                            <option
                              value={item.id + "," + item.branchName}
                              key={item.id}
                            >
                              {item.branchName}
                            </option>
                          ))}
                        </select>
                      </div>
                    ) : null}

                    {bySearch === "agent" && branchLoad && agentShow ? (
                      <div className="col-md-2">
                        <select
                          className="browser-default custom-select marginArea"
                          onChange={this.loadAgents}
                        >
                          <option>By Agent</option>
                          {agents.map(item => (
                            <option
                              value={item.firstName + " " + item.lastName}
                              key={item.id}
                            >
                              {item.firstName + " " + item.lastName}
                            </option>
                          ))}
                        </select>
                      </div>
                    ) : null}

                    {/* Row End  */}
                  </div>
                  <div className="row">
                    {sureDate ? (
                      <div className="col-md-10 mb-4">
                        {" "}
                        <CSVLink
                          data={csvFilterCustomerData}
                          headers={this.headers}
                          filename="customer_report.csv"
                        >
                          <i
                            className="fa fa-download agencyDefualt"
                            id="TooltipExample"
                          ></i>
                          <Tooltip
                            placement="right"
                            isOpen={this.state.tooltipOpen}
                            target="TooltipExample"
                            toggle={this.toggle}
                          >
                            export filter customers report
                          </Tooltip>
                        </CSVLink>
                      </div>
                    ) : (
                      <div className="col-md-10 mb-4">
                        {" "}
                        <CSVLink
                          data={csvCustomerData}
                          headers={this.headers}
                          filename="customer_report.csv"
                        >
                          <i
                            className="fa fa-download agencyDefualt"
                            id="TooltipExample"
                          ></i>
                          <Tooltip
                            placement="right"
                            isOpen={this.state.tooltipOpen}
                            target="TooltipExample"
                            toggle={this.toggle}
                          >
                            export customers report
                          </Tooltip>
                        </CSVLink>
                      </div>
                    )}
                  </div>
                  {isLoading ? (
                    <div
                      style={{
                        marginTop: "20px"
                      }}
                      className="text-center"
                    >
                      <h3 className="dimgray"> Loading Customers </h3>{" "}
                      <p className="dimgray"> Hold Your Horses! </p>{" "}
                      <Loader
                        type="ThreeDots"
                        color="#7AC953"
                        height="40"
                        width="40"
                      />
                    </div>
                  ) : customer_users && customer_users.data.rows.length ? (
                    <>
                      {" "}
                      <div className="data-showing">
                        Showing - {(this.state.pageNumber - 1) * 10 + 1}-
                        {this.state.pageNumber * 10 >= customer_users.data.count
                          ? customer_users.data.count
                          : this.state.pageNumber * 10 + " "}{" "}
                        / {customer_users.data.count}
                      </div>{" "}
                      <SaleTables
                        status={status}
                        customerReport={customer_users}
                      />
                      <div className="text-center">
                        {sureDate ? null : (
                          <>
                            <Pagination
                              className={"paginationCustomStyle"}
                              onChange={this.fetchAllCustomerData}
                              current={this.state.pageNumber}
                              total={customer_users.data.count}
                            />
                          </>
                        )}
                      </div>
                    </>
                  ) : (
                    <div style={{ marginTop: "20px" }} className="text-center">
                      <h3 className="dimgray">No Customers Found</h3>
                      <p className="dimgray">
                        You Have Not Added Any Customers
                      </p>
                    </div>
                  )}
                </div>
              </div>
            </div>
          </div>
        ) : null}
      </div>
    );
  }
}

const mapStateToProps = state => {
  return {
    customer_users: state.Customer.allFilterCustomers,
    isLoading: state.Customer.isLoading,
    status: state.Customer.status,
    cities: state.Customer.cities
  };
};

const mapDispatchToProps = dispatch => {
  return {
    fetchCustomers: (page, url) => dispatch(fetchAllCustomerData(page, url))
  };
};
export default connect(
  mapStateToProps,
  mapDispatchToProps
)(CustomerReport);

最佳答案

这可能是因为您在 componentDidMount 方法中进行了 AJAX 调用 (getAllCustomer)。如果响应在您的组件未安装时到达,则 resolve 回调中的 setState 将导致 React 警告。您最好在组件的 componentWillUnmount 方法中取消所有正在进行的 AJAX 调用。您可以使用 Axios 执行此操作:https://github.com/axios/axios#cancellation

你可以尝试这样的事情:

import React, { Component } from "react";
import { CSVLink } from "react-csv";
import moment from "moment";
import { connect } from "react-redux";
import axios from "axios";
import { fetchAllCustomerData } from "../../actions/customer";
import SaleTables from "./SaleTables";
import { DateRangePicker } from "react-dates";
import "react-dates/initialize";
import "react-dates/lib/css/_datepicker.css";
import Pagination from "rc-pagination";
import "rc-pagination/assets/index.css";
import Loader from "react-loader-spinner";
import "./style.css";
import { Tooltip } from "reactstrap";

class CustomerReport extends Component {
  constructor(props) {
    super(props);

    this.cancelTokenSource = new axios.CancelToken.source();


    this.state = {
      loading: true,
      pageNumber: 1,
      bySearch: "",
      cityName: "",
      tooltipOpen: false,
      branches: [],
      branchLoad: false,
      agentShow: false,
      dateShow: true,
      agents: [],
      status: "fetchAll",
      url: "/api/customer/all?limit=10",
      branchValue: "",
      searchInput: "",
      csvData: [],
      focusedInput: null,
      sureDate: false
    };
  }

  headers = [
    {
      label: "id",
      key: "id"
    },
    {
      label: "Name",
      key: "firstName"
    },
    {
      label: "Phone",
      key: "contact1"
    },
    {
      label: "Email",
      key: "email"
    },
    {
      label: "CNIC",
      key: "cnic"
    },
    {
      label: "Created",
      key: "createdAt"
    },
    {
      label: "Created by Agent",
      key: "byAgent"
    }
  ];

  componentDidMount() {
    this.fetchAllCustomerData();
    document.title = "Customer Report";
    this.getAllCustomer();
  }

  componentWillUnmount () {
      this.cancelTokenSource.cancel()
  }

  getAllCustomer = () => {
    axios.get("/api/customer/all", { cancelToken: this.cancelTokenSource.token })
        .then(res => {
          this.setState({
            csvData: res.data.rows
          });
        })
        .catch(e => {
            if (axios.isCancel(e)) {
                console.log('Axios call cancelled !')
            }
        });
  };

  fetchAllCustomerData = (pageNumber = 1) => {
    this.setState({
      pageNumber
    });
    const { url } = this.state;
    this.props.fetchCustomers(pageNumber, url);
  };

  handleSearchBy = e => {
    const { value } = e.target;
    this.setState({
      bySearch: value
    });
  };

  handleCity = e => {
    const { value } = e.target;
    axios.get(`/api/officeBranch/?searchBy=city&q=${value}`).then(res => {
      this.setState({
        branches: res.data.rows,
        branchLoad: true,
        url: this.state.url
      });
    });
  };

  handleChange = e => {
    this.setState({
      searchInput: e.target.value
    });
  };

  submitHandle = (e, pageNumber = 1) => {
    e.preventDefault();
    const url = `/api/customer/all?searchBy=id&offset=0&limit=10&q=${this.state.searchInput}`;
    this.setState({
      url
    });
    this.props.fetchCustomers(pageNumber, url);
  };

  fetchAgents = (e, pageNumber = 1) => {
    const { value } = e.target;
    let split = value.split(",");
    let url = `/api/customer/all?searchBy=branch&q=${split[1]}&limit=10`;
    this.setState({
      url,
      pageNumber: 1
    });

    axios
      .get(`/api/officebranch/branchAgents?officeBranchId=${value}`)
      .then(res => {
        this.setState({
          agents: res.data.rows,
          agentShow: true
        });
      });

    this.props.fetchCustomers(pageNumber, url);
  };

  toggle = () => {
    this.setState({
      tooltipOpen: !this.state.tooltipOpen
    });
  };

  loadAgents = (e, pageNumber = 1) => {
    const { value } = e.target;
    const url = `/api/customer/all?searchBy=agent&q=${value}&limit=10`;
    this.setState({
      url,
      pageNumber: 1
    });
    this.props.fetchCustomers(pageNumber, url);
  };

  handleDatesChange = (startDate, endDate, pageNumber = 1) => {
    if (startDate !== "" && endDate !== "") {
      let url = `/api/customer/all?fromDate=${startDate.format(
        "YYYY-MM-DD"
      )}&toDate=${endDate.format("YYYY-MM-DD")}`;
      this.setState({
        url,
        sureDate: true,
        pageNumber: 1,
        startDate: startDate,
        endDate: endDate
      });

      this.props.fetchCustomers(pageNumber, url);
    }
  };

  render() {
    const { customer_users, isLoading, status, cities } = this.props;
    const {
      bySearch,
      branchLoad,
      branches,
      agentShow,
      agents,
      startDate,
      endDate,
      sureDate
    } = this.state;
    let csvCustomerData = this.state.csvData.map(row => ({
      ...row,
      firstName: row.firstName + " " + row.lastName,
      createdAt: moment(row.createdAt).format("YYYY-MM-DD"),
      byAgent: row.user.firstName + " " + row.user.lastName,
      cnic: `=""${row.cnic}""`
    }));

    let csvFilterCustomerData =
      customer_users &&
      customer_users.data.rows.map(row => ({
        ...row,
        firstName: row.firstName + " " + row.lastName,
        createdAt: moment(row.createdAt).format("YYYY-MM-DD"),
        byAgent: row.user.firstName + " " + row.user.lastName,
        cnic: `=""${row.cnic}""`
      }));

    return (
      <div>
        {customer_users && customer_users.data.rows ? (
          <div className="pillsWrap">
            {/* Filters HTML */}
            <div className="filtersMain">
              <div className="row">
                <div className="col-md-12">
                  <div className="row">
                    <div className="col-md-2">
                      <div className="officeFilter">
                        <select
                          className="browser-default custom-select marginArea"
                          onChange={this.handleSearchBy}
                        >
                          <option> By </option>
                          <option value="id"> Id </option>
                          <option value="agent"> Agent </option>
                        </select>
                      </div>
                    </div>

                    {bySearch === "id" ? (
                      <div className="col-md-6">
                        <form onSubmit={this.submitHandle}>
                          <input
                            type="text"
                            name="search"
                            placeholder="Search.."
                            className="searchBox"
                            onChange={this.handleChange}
                            autoComplete="off"
                          />
                        </form>
                      </div>
                    ) : null}

                    {bySearch === "id" || bySearch === "agent" ? null : (
                      <div className="col-md-10 pull-right">
                        <div className="dateFilter">
                          <DateRangePicker
                            startDate={moment(startDate)}
                            endDate={moment(endDate)}
                            onDatesChange={dateData => {
                              this.handleDatesChange(
                                dateData.startDate,
                                dateData.endDate
                              );
                            }}
                            focusedInput={this.state.focusedInput}
                            onFocusChange={focusedInput =>
                              this.setState({ focusedInput })
                            }
                            startDateId="TASKS_FILTER_START_DATE_UNIQUE_ID"
                            endDateId="TASKS_FILTER_END_DATE_UNIQUE_ID"
                            numberOfMonths={1}
                            isOutsideRange={day => false}
                            displayFormat="MMM DD / YY"
                          />
                        </div>
                      </div>
                    )}

                    {bySearch === "agent" ? (
                      <div className="col-md-2">
                        <select
                          className="browser-default custom-select marginArea"
                          onChange={this.handleCity}
                        >
                          <option>By City</option>
                          {cities.data.map(item => (
                            <option value={item.name} key={item.id}>
                              {item.name}
                            </option>
                          ))}
                        </select>
                      </div>
                    ) : null}

                    {bySearch === "agent" && branchLoad ? (
                      <div className="col-md-2">
                        <select
                          className="browser-default custom-select marginArea"
                          onChange={this.fetchAgents}
                        >
                          <option>By Branch</option>
                          {branches.map(item => (
                            <option
                              value={item.id + "," + item.branchName}
                              key={item.id}
                            >
                              {item.branchName}
                            </option>
                          ))}
                        </select>
                      </div>
                    ) : null}

                    {bySearch === "agent" && branchLoad && agentShow ? (
                      <div className="col-md-2">
                        <select
                          className="browser-default custom-select marginArea"
                          onChange={this.loadAgents}
                        >
                          <option>By Agent</option>
                          {agents.map(item => (
                            <option
                              value={item.firstName + " " + item.lastName}
                              key={item.id}
                            >
                              {item.firstName + " " + item.lastName}
                            </option>
                          ))}
                        </select>
                      </div>
                    ) : null}

                    {/* Row End  */}
                  </div>
                  <div className="row">
                    {sureDate ? (
                      <div className="col-md-10 mb-4">
                        {" "}
                        <CSVLink
                          data={csvFilterCustomerData}
                          headers={this.headers}
                          filename="customer_report.csv"
                        >
                          <i
                            className="fa fa-download agencyDefualt"
                            id="TooltipExample"
                          ></i>
                          <Tooltip
                            placement="right"
                            isOpen={this.state.tooltipOpen}
                            target="TooltipExample"
                            toggle={this.toggle}
                          >
                            export filter customers report
                          </Tooltip>
                        </CSVLink>
                      </div>
                    ) : (
                      <div className="col-md-10 mb-4">
                        {" "}
                        <CSVLink
                          data={csvCustomerData}
                          headers={this.headers}
                          filename="customer_report.csv"
                        >
                          <i
                            className="fa fa-download agencyDefualt"
                            id="TooltipExample"
                          ></i>
                          <Tooltip
                            placement="right"
                            isOpen={this.state.tooltipOpen}
                            target="TooltipExample"
                            toggle={this.toggle}
                          >
                            export customers report
                          </Tooltip>
                        </CSVLink>
                      </div>
                    )}
                  </div>
                  {isLoading ? (
                    <div
                      style={{
                        marginTop: "20px"
                      }}
                      className="text-center"
                    >
                      <h3 className="dimgray"> Loading Customers </h3>{" "}
                      <p className="dimgray"> Hold Your Horses! </p>{" "}
                      <Loader
                        type="ThreeDots"
                        color="#7AC953"
                        height="40"
                        width="40"
                      />
                    </div>
                  ) : customer_users && customer_users.data.rows.length ? (
                    <>
                      {" "}
                      <div className="data-showing">
                        Showing - {(this.state.pageNumber - 1) * 10 + 1}-
                        {this.state.pageNumber * 10 >= customer_users.data.count
                          ? customer_users.data.count
                          : this.state.pageNumber * 10 + " "}{" "}
                        / {customer_users.data.count}
                      </div>{" "}
                      <SaleTables
                        status={status}
                        customerReport={customer_users}
                      />
                      <div className="text-center">
                        {sureDate ? null : (
                          <>
                            <Pagination
                              className={"paginationCustomStyle"}
                              onChange={this.fetchAllCustomerData}
                              current={this.state.pageNumber}
                              total={customer_users.data.count}
                            />
                          </>
                        )}
                      </div>
                    </>
                  ) : (
                    <div style={{ marginTop: "20px" }} className="text-center">
                      <h3 className="dimgray">No Customers Found</h3>
                      <p className="dimgray">
                        You Have Not Added Any Customers
                      </p>
                    </div>
                  )}
                </div>
              </div>
            </div>
          </div>
        ) : null}
      </div>
    );
  }
}

const mapStateToProps = state => {
  return {
    customer_users: state.Customer.allFilterCustomers,
    isLoading: state.Customer.isLoading,
    status: state.Customer.status,
    cities: state.Customer.cities
  };
};

const mapDispatchToProps = dispatch => {
  return {
    fetchCustomers: (page, url) => dispatch(fetchAllCustomerData(page, url))
  };
};
export default connect(
  mapStateToProps,
  mapDispatchToProps
)(CustomerReport);

关于javascript - react : Warning: Can't perform a React state update on an unmounted component,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58110371/

相关文章:

javascript - 将数据值存储在 JSON 文件中

javascript - 序列化嵌套模型的 where 条件

javascript - React getDerivedStateFromProps() 的使用

reactjs - 我们应该使用 PropTypes 来处理 Redux 状态吗?

javascript - 带有 redux 的 RxJS - 完成时发出 Action (使用 mergeMap)

javascript - 观察外部模型的 Angular Directive(指令)

javascript - 嵌套 .then() 函数

node.js - 无法创建 react 新项目

javascript - 使用 React.JS 向容器填充内容

javascript - 从函数返回修改后的新对象