当我想显示来自 API 的数据时出错
error when I want to display data from an API
在我尝试放置的屏幕中。我得到了产品的 ID。上一个屏幕是来自 API 的产品列表。感谢 props.data 我得到了这个 ID
console.log ('props', this.props.data) 工作正常并且 returns 对我来说是正确的 ID,无论点击的是什么产品。
有了这个产品的ID,我想找到这个产品的详细信息(参考,系列,价格,库存等)。
我创建了这个函数来通过我的 API.
调用产品详细信息
initListData = async () => {
if (parseInt(this.state.productId) > 0) {
let product_data = await getProduct(this.state.productId);
console.log('product_data', product_data)
this.setState({
displayArray: product_data,
loadMoreVisible: (product_data.length >= 15 ? true : false),
currentPage: 2
});
}
};
我认为问题是 displayArray[] 是空的所以
let product_data = await getProduct(this.state.productId);
无效。
我收到此错误:无法从不同组件的函数体内部更新组件
你能给我解释一下这是怎么回事吗?
完整代码
export default class Information extends Component {
constructor(props) {
super(props);
this.state = {
productId: this.props.data,
displayArray: [],
}
console.log('props', this.props.data) // ok, ça fonctionne, on récupère bien l'ID du produit cliqué
};
initListData = async () => {
if (parseInt(this.state.productId) > 0) {
let product_data = await getProduct(this.state.productId);
console.log('product_data', product_data)
this.setState({
displayArray: product_data,
loadMoreVisible: (product_data.length >= 15 ? true : false),
currentPage: 2
});
}
};
async UNSAFE_componentWillMount() {
this.initListData();
}
render() {
console.log('ça c\'est data = ', this.props.data );
console.log('ça c\'est les props =', this.props );
console.log('ça c\'est le state = ', this.state );
return (
<ScrollView contentContainerStyle={{flex: 1}}>
{
this.state.displayArray.map((item, i) => (
<ListItem bottomDivider>
<Icon name='flight-takeoff' />
<ListItem.Content>
<ListItem.Title style={{color: '#d35400'}}>{item.name}</ListItem.Title>
<ListItem.Subtitle style={{ color: '#F78400' }}>
{i18n.t("information.family")}: {item.family_id}
</ListItem.Subtitle>
<ListItem.Subtitle style={{ color: '#F78400' }}>
{i18n.t("information.reference")}: {item.reference}
</ListItem.Subtitle>
<ListItem.Subtitle style={{ color: '#F78400' }}>
{i18n.t("information.id")}: {item.id}
</ListItem.Subtitle>
<ListItem.Subtitle style={{ color: '#F78400' }}>
{i18n.t("information.cost")}: {item.cost}
</ListItem.Subtitle>
<ListItem.Subtitle style={{ color: '#F78400' }}>
{i18n.t("information.description")}: {item.description}
</ListItem.Subtitle>
<ListItem.Subtitle style={{ color: '#F78400' }}>
{i18n.t("information.stock")}: {item.stock_status}
</ListItem.Subtitle>
</ListItem.Content>
</ListItem>
))
}
</ScrollView>
);
}
}
getProduct 函数:[我只需要隐藏真实的 url]
export async function getProduct(product_id) {
const abortController = new AbortController();
let user_id = await retrieveProfileUserId();
let lang = await retrieveAppLang();
let access_token = await renewAccessToken();
let result = {};
if (parseInt(product_id) > 0 && access_token != '' && parseInt(user_id) > 0) {
try {
let response = await fetch(
API_URL +
"/products/" + product_id +
"?user_id=" + user_id +
"&society_id=" + API_SOCIETYID +
"&access_token=" + access_token +
"&lang=" + lang,
{
method: "GET",
signal: abortController.signal,
headers: {
Accept: "application/json",
"Content-Type": "application/json",
Authorization: "Bearer " + API_SECRETKEY,
"Cache-Control": "no-cache, no-store, must-revalidate",
Pragma: "no-cache",
Expires: "0"
}
}
)
.then(response => response.json())
.then(responseData => {
if (responseData.status == 200 && responseData.data) {
console.log("getProduct()::success", responseData.data);
result = responseData.data;
} else if (
responseData.status >= 200 && responseData.status <= 404 &&
responseData.data.error && responseData.data.error.length >= 3
) {
// Handle error
throw responseData.data.error;
} else {
throw "error";
}
});
} catch (error) {
//console.log(error);
abortController.abort();
}
}
尝试改变一些东西,它应该会起作用。
我也不喜欢直接在fn里面设置state,所以我提出如下修改:
initListData = async () => {
if (this.props.data != null) {
const productData = await getProduct(this.state.productId);
return productData; // You are missing this, this is vital!
}
};
async componentDidMount() {
const data = await this.initListData(); // don't forget await here if you're using async
if (data.id) {
this.setState((prevState) => ({
displayArray: [...prevState.displayArray, data],
loadMoreVisible: ..., // I don't know what do you want here, because again, you receive an object from your backend, not an array.
currentPage: 2
}));
}
}
为了确保这一点很清楚,我 post 一个答案来显示我现在拥有的代码。
我希望我正确理解了康斯坦丁先生的解释,如果不是这样,我深表歉意,我按照你向我建议的 initListData 和 componentWillUnMount 进行了修改,但我的印象是我们没有输入 componentDidMount,displayArray 是空的。
在终端我的 console.log 给出:
props 16
this is displayArray = Array []
我没有 console.log('productData=', productData)
我收到 3 个黄色错误:
[Unhandled promise rejection: ReferenceError: Can't find variable:
productData]
[Unhandled promise rejection: TypeError: this.initListData is not a
function. (In 'this.initListData()', 'this.initListData' is undefined)
[Unhandled promise rejection: TypeError: undefined is not an object
(evaluating 'data.length')]
export default class Information extends Component {
constructor(props) {
super(props);
this.state = {
productId: this.props.data,
displayArray: [],
}
console.log('props', this.props.data) // ok, ça fonctionne, on récupère bien l'ID du produit cliqué
};
initListData = async () => {
if (this.props.data != null) {
console.log('this.props.data =', this.props.data) // OK
const productData = await getProduct(this.state.productId);
}
};
async componentDidMount() {
console.log('productData=', productData)
const data = await this.initListData(); // don't forget await here if you're using async
console.log('data', data)
if (data.length) {
this.setState({
displayArray: data,
loadMoreVisible: data.length >= 15, // no need for ternary
currentPage: 2
});
}
}
render() {
console.log('this is displayArray = ', this.state.displayArray );
return (
<ScrollView contentContainerStyle={{flex: 1}}>
{
this.state.displayArray.map((item, i) => (
<ListItem bottomDivider>
<Icon name='flight-takeoff' />
<ListItem.Content>
<ListItem.Title style={{color: '#d35400'}}>{item.name}</ListItem.Title>
<ListItem.Subtitle style={{ color: '#F78400' }}>
{i18n.t("information.family")}: {item.family_id}
</ListItem.Subtitle>
<ListItem.Subtitle style={{ color: '#F78400' }}>
{i18n.t("information.reference")}: {item.reference}
</ListItem.Subtitle>
<ListItem.Subtitle style={{ color: '#F78400' }}>
{i18n.t("information.id")}: {item.id}
</ListItem.Subtitle>
<ListItem.Subtitle style={{ color: '#F78400' }}>
{i18n.t("information.cost")}: {item.cost}
</ListItem.Subtitle>
<ListItem.Subtitle style={{ color: '#F78400' }}>
{i18n.t("information.description")}: {item.description}
</ListItem.Subtitle>
<ListItem.Subtitle style={{ color: '#F78400' }}>
{i18n.t("information.stock")}: {item.stock_status}
</ListItem.Subtitle>
</ListItem.Content>
</ListItem>
))
}
</ScrollView>
);
}
}
------------------------编辑---------------- ----------
修改后:
export default class Information extends Component {
constructor(props) {
super(props);
this.state = {
productId: this.props.data,
displayArray: [],
}
console.log('props', this.props.data) // ok, ça fonctionne, on récupère bien l'ID du produit cliqué
};
initListData = async () => {
if (this.props.data != null) {
console.log('this.props.data =', this.props.data) // OK
let productData = await getProduct(this.props.data);
console.log('productData =', productData )
}
};
async componentDidMount() {
const data = await this.initListData(); // don't forget await here if you're using async
console.log('data', data)
if (data.length) {
this.setState({
displayArray: data,
loadMoreVisible: data.length >= 15, // no need for ternary
currentPage: 2
});
}
return data;
}
render() {
console.log('this is displayArray = ', this.state.displayArray);
return (
<ScrollView contentContainerStyle={{flex: 1}}>
{
this.state.displayArray.map((item, i) => (
<ListItem bottomDivider>
<Icon name='flight-takeoff' />
<ListItem.Content>
<ListItem.Title style={{color: '#d35400'}}>{item.name}</ListItem.Title>
<ListItem.Subtitle style={{ color: '#F78400' }}>
{i18n.t("information.family")}: {item.family_id}
</ListItem.Subtitle>
<ListItem.Subtitle style={{ color: '#F78400' }}>
{i18n.t("information.reference")}: {item.reference}
</ListItem.Subtitle>
<ListItem.Subtitle style={{ color: '#F78400' }}>
{i18n.t("information.id")}: {item.id}
</ListItem.Subtitle>
<ListItem.Subtitle style={{ color: '#F78400' }}>
{i18n.t("information.cost")}: {item.cost}
</ListItem.Subtitle>
<ListItem.Subtitle style={{ color: '#F78400' }}>
{i18n.t("information.description")}: {item.description}
</ListItem.Subtitle>
<ListItem.Subtitle style={{ color: '#F78400' }}>
{i18n.t("information.stock")}: {item.stock_status}
</ListItem.Subtitle>
</ListItem.Content>
</ListItem>
))
}
</ScrollView>
);
}
}
在控制台中:
this is displayArray = Array []
productData = Object { "cost": 1.86, "created_at":
"2018-05-17T21:27:22Z", "custom_fields": Array [], "description":
"", "family_id": 1, "id": 16, "incl_tax": 1, "is_visible": 1,
"name": "", "photo": Object {
"1": Object {
"id": 1,
"order": 1,
"title_fr": "tomato-ketchup-flacon-souple",
"url": "/i/p-6-1-6-146_5844_16_1.jpg",
}, }, "quantity": "0", "reference": "", "stock_status": "0", "tax_rate_id": 1, "unit": "", "updated_at":
"2018-05-17T21:27:24Z", "weight": 0, }
data undefined
错误:
[Unhandled promise rejection: TypeError: undefined is not an object
(evaluating 'data.length')]
空白页
在我尝试放置的屏幕中。我得到了产品的 ID。上一个屏幕是来自 API 的产品列表。感谢 props.data 我得到了这个 ID console.log ('props', this.props.data) 工作正常并且 returns 对我来说是正确的 ID,无论点击的是什么产品。 有了这个产品的ID,我想找到这个产品的详细信息(参考,系列,价格,库存等)。 我创建了这个函数来通过我的 API.
调用产品详细信息initListData = async () => {
if (parseInt(this.state.productId) > 0) {
let product_data = await getProduct(this.state.productId);
console.log('product_data', product_data)
this.setState({
displayArray: product_data,
loadMoreVisible: (product_data.length >= 15 ? true : false),
currentPage: 2
});
}
};
我认为问题是 displayArray[] 是空的所以
let product_data = await getProduct(this.state.productId);
无效。
我收到此错误:无法从不同组件的函数体内部更新组件 你能给我解释一下这是怎么回事吗?
完整代码
export default class Information extends Component {
constructor(props) {
super(props);
this.state = {
productId: this.props.data,
displayArray: [],
}
console.log('props', this.props.data) // ok, ça fonctionne, on récupère bien l'ID du produit cliqué
};
initListData = async () => {
if (parseInt(this.state.productId) > 0) {
let product_data = await getProduct(this.state.productId);
console.log('product_data', product_data)
this.setState({
displayArray: product_data,
loadMoreVisible: (product_data.length >= 15 ? true : false),
currentPage: 2
});
}
};
async UNSAFE_componentWillMount() {
this.initListData();
}
render() {
console.log('ça c\'est data = ', this.props.data );
console.log('ça c\'est les props =', this.props );
console.log('ça c\'est le state = ', this.state );
return (
<ScrollView contentContainerStyle={{flex: 1}}>
{
this.state.displayArray.map((item, i) => (
<ListItem bottomDivider>
<Icon name='flight-takeoff' />
<ListItem.Content>
<ListItem.Title style={{color: '#d35400'}}>{item.name}</ListItem.Title>
<ListItem.Subtitle style={{ color: '#F78400' }}>
{i18n.t("information.family")}: {item.family_id}
</ListItem.Subtitle>
<ListItem.Subtitle style={{ color: '#F78400' }}>
{i18n.t("information.reference")}: {item.reference}
</ListItem.Subtitle>
<ListItem.Subtitle style={{ color: '#F78400' }}>
{i18n.t("information.id")}: {item.id}
</ListItem.Subtitle>
<ListItem.Subtitle style={{ color: '#F78400' }}>
{i18n.t("information.cost")}: {item.cost}
</ListItem.Subtitle>
<ListItem.Subtitle style={{ color: '#F78400' }}>
{i18n.t("information.description")}: {item.description}
</ListItem.Subtitle>
<ListItem.Subtitle style={{ color: '#F78400' }}>
{i18n.t("information.stock")}: {item.stock_status}
</ListItem.Subtitle>
</ListItem.Content>
</ListItem>
))
}
</ScrollView>
);
}
}
getProduct 函数:[我只需要隐藏真实的 url]
export async function getProduct(product_id) {
const abortController = new AbortController();
let user_id = await retrieveProfileUserId();
let lang = await retrieveAppLang();
let access_token = await renewAccessToken();
let result = {};
if (parseInt(product_id) > 0 && access_token != '' && parseInt(user_id) > 0) {
try {
let response = await fetch(
API_URL +
"/products/" + product_id +
"?user_id=" + user_id +
"&society_id=" + API_SOCIETYID +
"&access_token=" + access_token +
"&lang=" + lang,
{
method: "GET",
signal: abortController.signal,
headers: {
Accept: "application/json",
"Content-Type": "application/json",
Authorization: "Bearer " + API_SECRETKEY,
"Cache-Control": "no-cache, no-store, must-revalidate",
Pragma: "no-cache",
Expires: "0"
}
}
)
.then(response => response.json())
.then(responseData => {
if (responseData.status == 200 && responseData.data) {
console.log("getProduct()::success", responseData.data);
result = responseData.data;
} else if (
responseData.status >= 200 && responseData.status <= 404 &&
responseData.data.error && responseData.data.error.length >= 3
) {
// Handle error
throw responseData.data.error;
} else {
throw "error";
}
});
} catch (error) {
//console.log(error);
abortController.abort();
}
}
尝试改变一些东西,它应该会起作用。
我也不喜欢直接在fn里面设置state,所以我提出如下修改:
initListData = async () => {
if (this.props.data != null) {
const productData = await getProduct(this.state.productId);
return productData; // You are missing this, this is vital!
}
};
async componentDidMount() {
const data = await this.initListData(); // don't forget await here if you're using async
if (data.id) {
this.setState((prevState) => ({
displayArray: [...prevState.displayArray, data],
loadMoreVisible: ..., // I don't know what do you want here, because again, you receive an object from your backend, not an array.
currentPage: 2
}));
}
}
为了确保这一点很清楚,我 post 一个答案来显示我现在拥有的代码。 我希望我正确理解了康斯坦丁先生的解释,如果不是这样,我深表歉意,我按照你向我建议的 initListData 和 componentWillUnMount 进行了修改,但我的印象是我们没有输入 componentDidMount,displayArray 是空的。 在终端我的 console.log 给出:
props 16 this is displayArray = Array []
我没有 console.log('productData=', productData)
我收到 3 个黄色错误:
[Unhandled promise rejection: ReferenceError: Can't find variable: productData]
[Unhandled promise rejection: TypeError: this.initListData is not a function. (In 'this.initListData()', 'this.initListData' is undefined)
[Unhandled promise rejection: TypeError: undefined is not an object (evaluating 'data.length')]
export default class Information extends Component {
constructor(props) {
super(props);
this.state = {
productId: this.props.data,
displayArray: [],
}
console.log('props', this.props.data) // ok, ça fonctionne, on récupère bien l'ID du produit cliqué
};
initListData = async () => {
if (this.props.data != null) {
console.log('this.props.data =', this.props.data) // OK
const productData = await getProduct(this.state.productId);
}
};
async componentDidMount() {
console.log('productData=', productData)
const data = await this.initListData(); // don't forget await here if you're using async
console.log('data', data)
if (data.length) {
this.setState({
displayArray: data,
loadMoreVisible: data.length >= 15, // no need for ternary
currentPage: 2
});
}
}
render() {
console.log('this is displayArray = ', this.state.displayArray );
return (
<ScrollView contentContainerStyle={{flex: 1}}>
{
this.state.displayArray.map((item, i) => (
<ListItem bottomDivider>
<Icon name='flight-takeoff' />
<ListItem.Content>
<ListItem.Title style={{color: '#d35400'}}>{item.name}</ListItem.Title>
<ListItem.Subtitle style={{ color: '#F78400' }}>
{i18n.t("information.family")}: {item.family_id}
</ListItem.Subtitle>
<ListItem.Subtitle style={{ color: '#F78400' }}>
{i18n.t("information.reference")}: {item.reference}
</ListItem.Subtitle>
<ListItem.Subtitle style={{ color: '#F78400' }}>
{i18n.t("information.id")}: {item.id}
</ListItem.Subtitle>
<ListItem.Subtitle style={{ color: '#F78400' }}>
{i18n.t("information.cost")}: {item.cost}
</ListItem.Subtitle>
<ListItem.Subtitle style={{ color: '#F78400' }}>
{i18n.t("information.description")}: {item.description}
</ListItem.Subtitle>
<ListItem.Subtitle style={{ color: '#F78400' }}>
{i18n.t("information.stock")}: {item.stock_status}
</ListItem.Subtitle>
</ListItem.Content>
</ListItem>
))
}
</ScrollView>
);
}
}
------------------------编辑---------------- ----------
修改后:
export default class Information extends Component {
constructor(props) {
super(props);
this.state = {
productId: this.props.data,
displayArray: [],
}
console.log('props', this.props.data) // ok, ça fonctionne, on récupère bien l'ID du produit cliqué
};
initListData = async () => {
if (this.props.data != null) {
console.log('this.props.data =', this.props.data) // OK
let productData = await getProduct(this.props.data);
console.log('productData =', productData )
}
};
async componentDidMount() {
const data = await this.initListData(); // don't forget await here if you're using async
console.log('data', data)
if (data.length) {
this.setState({
displayArray: data,
loadMoreVisible: data.length >= 15, // no need for ternary
currentPage: 2
});
}
return data;
}
render() {
console.log('this is displayArray = ', this.state.displayArray);
return (
<ScrollView contentContainerStyle={{flex: 1}}>
{
this.state.displayArray.map((item, i) => (
<ListItem bottomDivider>
<Icon name='flight-takeoff' />
<ListItem.Content>
<ListItem.Title style={{color: '#d35400'}}>{item.name}</ListItem.Title>
<ListItem.Subtitle style={{ color: '#F78400' }}>
{i18n.t("information.family")}: {item.family_id}
</ListItem.Subtitle>
<ListItem.Subtitle style={{ color: '#F78400' }}>
{i18n.t("information.reference")}: {item.reference}
</ListItem.Subtitle>
<ListItem.Subtitle style={{ color: '#F78400' }}>
{i18n.t("information.id")}: {item.id}
</ListItem.Subtitle>
<ListItem.Subtitle style={{ color: '#F78400' }}>
{i18n.t("information.cost")}: {item.cost}
</ListItem.Subtitle>
<ListItem.Subtitle style={{ color: '#F78400' }}>
{i18n.t("information.description")}: {item.description}
</ListItem.Subtitle>
<ListItem.Subtitle style={{ color: '#F78400' }}>
{i18n.t("information.stock")}: {item.stock_status}
</ListItem.Subtitle>
</ListItem.Content>
</ListItem>
))
}
</ScrollView>
);
}
}
在控制台中:
this is displayArray = Array []
productData = Object { "cost": 1.86, "created_at": "2018-05-17T21:27:22Z", "custom_fields": Array [], "description": "", "family_id": 1, "id": 16, "incl_tax": 1, "is_visible": 1, "name": "", "photo": Object { "1": Object { "id": 1, "order": 1, "title_fr": "tomato-ketchup-flacon-souple", "url": "/i/p-6-1-6-146_5844_16_1.jpg", }, }, "quantity": "0", "reference": "", "stock_status": "0", "tax_rate_id": 1, "unit": "", "updated_at": "2018-05-17T21:27:24Z", "weight": 0, }
data undefined
错误:
[Unhandled promise rejection: TypeError: undefined is not an object (evaluating 'data.length')]
空白页