How to setstate in a loop?

北慕城南 提交于 2020-06-17 14:11:38

问题


i am getting error at this.setState({ Url: resp.data.Url }); in GETAPI TypeError: Cannot read property 'setState' of undefined.. Please suggest. The GETAPI is basically used to render the data from the API. My use-case is to store all the URLs in state and pass it to DownloadButton component. I need this URL to download the required data.

The hirerachy of code is invokeGetReport which will give all the reports in array. I have looped in and invoked invokeGetReportDetails method. Under invokeGetReportDetails , i am calling invokeImageURL which will contain the URL'of all the reports. I need to store all the URLs in state & passed it to next component

class GetAPI extends Component {
  constructor(props) {
    super(props);
    this.state = {
      ID: [],
      Url: [],
    };
  }

  componentDidMount() {

    console.log(this.props.exptype);
    var accesstoken;
    let reports = [];

    axios
      .post(API, qs.stringify(requestBody), config)
      .then((result) => {
        console.log(result);
        this.setState({ token: result.data.access_token });
        accesstoken = result.data.access_token;
        console.log("access token ins " + accesstoken);
        invokeGetReport(accesstoken);
      })
      .catch((error) => {
        console.log(error);
        console.log(error.data);
      });

    function invokeGetReport(accesstoken) {
      console.log("access token is " + accesstoken);
      const config_req = {
        headers: {
          Accept: "application/json",
          Authorization: "Bearer " + accesstoken,
        },
      };

      axios
        .get(test_report_url, config_req)
        .then((resp) => {
          console.log(resp);
          console.log("data id is " + resp.data.Items.length);

          //  debugger;
          for (let i = 0; i < resp.data.Items.length; i++) {
            let reportName = resp.data.Items[i].Name;
            let reportID = resp.data.Items[i].ID;
            console.log("id is : " + reportID + "Report Name : " + reportName);
            invokeGetReportDetails(accesstoken, reportID);
            reports.push(reportID);
          }
          //  invokeGetReportDetails(accesstoken, reports);
        })
        .catch((error) => {
          console.log(error);
          console.log(error.data);
        });
    }

    function invokeGetReportDetails(accesstoken, reportID) {
      console.log("reportID in detail API is " + reportID);
      const config_req = {
        headers: {
          Accept: "application/json",
          Authorization: "Bearer " + accesstoken,
        },
      };

      axios
        .get(report_details + reportID, config_req)
        .then((resp) => {
          console.log(resp);
          console.log(
            "report data id is " + resp.data.ExpenseEntriesList.length
          );
          for (let i = 0; i < resp.data.ExpenseEntriesList.length; i++) {
            let expenseEntryId = resp.data.ExpenseEntriesList[i].ReportEntryID;
            let ExpenseTypeName =
              resp.data.ExpenseEntriesList[i].ExpenseTypeName;
            console.log(
              "id is : " +
                expenseEntryId +
                " ExpenseTypeName : " +
                ExpenseTypeName
            );
            invokeImageURL(accesstoken, expenseEntryId);
          }
        })
        .catch((error) => {
          console.log(error);
          console.log(error.data);
        });
    }

    function invokeImageURL(accesstoken, expenseEntryId) {
      console.log("expenseEntryId in detail API is " + expenseEntryId);

      const config_req = {
        headers: {
          Accept: "application/json",
          Authorization: "Bearer " + accesstoken,
        },
      };

      axios
        .get(image_url + expenseEntryId, config_req)
        .then((resp) => {
          console.log(resp);
          console.log("URL is " + resp.data.Url);
          this.setState({ Url: resp.data.Url });
        })
        .catch((error) => {
          console.log(error);
          console.log(error.data);
        });
    }

    console.log("repoddrts sdda " + reports[1]);
    console.log("prop value is " + this.props);
    // console.log("report id " + this.state.ID);
  }

  render() {
   return (
      <div>
        <DownloadButton imageUrl={this.Url} />
      </div>
    );
  }
}

export default GetAPI;

回答1:


This error is because this is not referrring to GetAPI component and that's because the way you have nested multiple functions inside componentDidMount function.

Write all those functions outside the componentDidMount function and use arrow functions.

Not related to the error but you are also not updating the state correctly. You are overwriting it instead of appending the new url to the existing list of urls.

Change

this.setState({ Url: resp.data.Url });

to

this.setState({ Url: [...this.state.Url, resp.data.Url] });

Here's the fixed code

class GetAPI extends Component {
  constructor(props) {
    super(props);
    this.state = {
      ID: [],
      Url: [],
    };
  }

  componentDidMount() {
    console.log(this.props.exptype);
    var accesstoken;
    let reports = [];

    axios
      .post(API, qs.stringify(requestBody), config)
      .then((result) => {
        console.log(result);
        this.setState({ token: result.data.access_token });
        accesstoken = result.data.access_token;
        console.log("access token ins " + accesstoken);
        this.invokeGetReport(accesstoken);
      })
      .catch((error) => {
        console.log(error);
        console.log(error.data);
      });

    console.log("repoddrts sdda " + reports[1]);
    console.log("prop value is " + this.props);
    // console.log("report id " + this.state.ID);
  }

  invokeGetReportDetails = (accesstoken, reportID) => {
      console.log("reportID in detail API is " + reportID);
      const config_req = {
        headers: {
          Accept: "application/json",
          Authorization: "Bearer " + accesstoken,
        },
      };

      axios
        .get(report_details + reportID, config_req)
        .then((resp) => {
          console.log(resp);
          console.log(
            "report data id is " + resp.data.ExpenseEntriesList.length
          );
          for (let i = 0; i < resp.data.ExpenseEntriesList.length; i++) {
            let expenseEntryId = resp.data.ExpenseEntriesList[i].ReportEntryID;
            let ExpenseTypeName =
              resp.data.ExpenseEntriesList[i].ExpenseTypeName;
            console.log(
              "id is : " +
                expenseEntryId +
                " ExpenseTypeName : " +
                ExpenseTypeName
            );
            this.invokeImageURL(accesstoken, expenseEntryId);
          }
        })
        .catch((error) => {
          console.log(error);
          console.log(error.data);
        });
  }

  invokeImageURL = (accesstoken, expenseEntryId) => {
      console.log("expenseEntryId in detail API is " + expenseEntryId);

      const config_req = {
        headers: {
          Accept: "application/json",
          Authorization: "Bearer " + accesstoken,
        },
      };

      axios
        .get(image_url + expenseEntryId, config_req)
        .then((resp) => {
          console.log(resp);
          console.log("URL is " + resp.data.Url);
          this.setState({ Url: [...this.state.Url, resp.data.Url] });
        })
        .catch((error) => {
          console.log(error);
          console.log(error.data);
        });
  }

  invokeGetReport = (accesstoken) => {
      console.log("access token is " + accesstoken);
      const config_req = {
        headers: {
          Accept: "application/json",
          Authorization: "Bearer " + accesstoken,
        },
      };

      axios
        .get(test_report_url, config_req)
        .then((resp) => {
            console.log(resp);
            console.log("data id is " + resp.data.Items.length);

            //  debugger;
            for (let i = 0; i < resp.data.Items.length; i++) {
              let reportName = resp.data.Items[i].Name;
              let reportID = resp.data.Items[i].ID;
              console.log("id is : " + reportID + "Report Name : " + reportName);
              this.invokeGetReportDetails(accesstoken, reportID);
              reports.push(reportID);
            }
          //  invokeGetReportDetails(accesstoken, reports);
        })
        .catch((error) => {
          console.log(error);
          console.log(error.data);
        });
  }

  render() {
   return (
      <div>
        <DownloadButton imageUrl={this.Url} />
      </div>
    );
  }
}

export default GetAPI;



回答2:


In the context of your functions there is no 'this'. Move your methods invokeGetReport, invokeGetReportDetails and invokeImageURL to class GetAPI and call them through 'this'.

class GetAPI extends Component {

    componentDidMount() {
        ...
          this.invokeGetReport(accesstoken);
        ...
    }

    invokeGetReportDetails = (accesstoken, reportID) => {
        ...
          this.invokeImageURL(accesstoken, expenseEntryId);
        ...
    };

    invokeImageURL = (accesstoken, expenseEntryId) => {
        ...
         this.setState({ Url: resp.data.Url });
        ...
    };

    invokeGetReport = (accesstoken) => {
        ...
         this.invokeGetReportDetails(accesstoken, reportID);
        ...
    };

    render() {
        ...
    }
}

export default GetAPI;

Or use lambda-functions:

const invokeGetReportDetails = (accesstoken, reportID) => {...}
const invokeImageURL = (accesstoken, expenseEntryId) => {...}

etc

Or call them through fn.call(this)



来源:https://stackoverflow.com/questions/62130045/how-to-setstate-in-a-loop

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!