问题
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