[英]React Native: How to render muliple images dynamically after fetching from multiple rest api's
I am unable to render multiple images fetched from multiple calls to rest API in react native.我无法渲染从多次调用中获取的多个图像,以在 React Native 中对 rest API 进行调用。
For Rest API reference, I am using woocommerce rest API for getting order details.对于 Rest API 参考,我使用 woocommerce rest API 来获取订单详细信息。 https://woocommerce.github.io/woocommerce-rest-api-docs/#retrieve-an-order
https://woocommerce.github.io/woocommerce-rest-api-docs/#retrieve-an-order
The problem is that order details don't have primary image of line_items
in rest API.问题是订单详细信息在 rest API 中没有
line_items
主要图像。 So I need to call each below product detail API for fetching product images for each line_item object via product_id
by again calling product details rest API.因此,我需要调用下面的每个产品详细信息 API,以通过再次调用产品详细信息 rest API 来通过
product_id
获取每个 line_item 对象的产品图像。
https://woocommerce.github.io/woocommerce-rest-api-docs/#retrieve-a-product https://woocommerce.github.io/woocommerce-rest-api-docs/#retrieve-a-product
Till now I have written the logic to call product details for each line_items but I am getting following error with my code.到目前为止,我已经编写了为每个 line_items 调用产品详细信息的逻辑,但是我的代码出现以下错误。 What would be the best way to handle this situation?
处理这种情况的最佳方法是什么?
Warning: Cannot update during an existing state transition (such as within `render`). Render methods should be a pure function of props and state.
Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.
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 %s.%s, the componentWillUnmount method,
Below is my implementation:下面是我的实现:
render() {
if (this.state.loading) {
return (
<View style={{ flex: 1, justifyContent: "center", alignContent: "center", padding: 20 }}>
<ActivityIndicator color='#96588a' size='large' />
</View>
)
}
return (
<ScrollView style={{ flex: 1 }}>
{this.displayOrderDataSection()}
{this.displayProductSection()}
{this.displayPaymentSection()}
{this.displayShippingDetailsSection()}
{this.displayBillingDetailsSection()}
</ScrollView>
);
}
getProductPrimaryImage = (productId) => {
let productData = null;
this.setState({ imageLoading: true });
let url = `${base_url}/wp-json/wc/v3/products/${productId}?consumer_key=${c_key}&consumer_secret=${c_secret}`
console.log(url);
fetch(url)
.then((response) => response.json())
.then((responseJson) => {
this.setState({
imageLoading: false,
error: responseJson.code || null,
});
productData = responseJson
})
.then(() => {
return productData ?
((Array.isArray(productData.images) && productData.images.length) ?
productData.images[0].src : null)
: null;
})
.catch((error) => {
this.setState({
error,
imageLoading: false,
})
});
}
getLineItems = () => {
let itemArray = [];
orderData.line_items.forEach(item => {
let imgSrc = this.getProductPrimaryImage(item.product_id)
itemArray.push(
<View key={item.id} style={{ flex: 1, flexDirection: 'row', backgroundColor: 'white' }}>
<View style={{ flex: 1, justifyContent: "center", alignContent: "center" }}>
<Image source={imgSrc}
style={{ height: 100, width: 100 }} resizeMode='contain' />
</View>
<View style={{ flex: 2, marginTop: 10, marginBottom: 10, justifyContent: "center" }}>
<View style={{ marginLeft: 10 }}>
<Text>{item.name}</Text>
<Text>SKU: {item.sku}</Text>
<Text>Price: {this.getCurrencySymbol()}{item.price.toFixed(2)}</Text>
<Text>Oty: {item.quantity}</Text>
<View>{this.getTMProductOptions(item.meta_data)}</View>
</View>
</View>
</View>
)
})
return itemArray;
}
displayProductSection = () => {
return (
<View style={styles.section}>
<Text style={styles.titleText}>Product</Text>
{this.getLineItems()}
</View>
)
}
The way to think about the render() method is that it may run repeatedly.考虑 render() 方法的方式是它可能会重复运行。 In most cases it is re-run every time there's a change that affects its output.
在大多数情况下,每次发生影响其输出的更改时都会重新运行它。
The way you have it structured, your render() function calls {this.displayProductSection()}
which calls this.getLineItems()
which calls this.getProductPrimaryImage(item.product_id)
which makes the AJAX request to the WordPress API.你有它的结构的方式,渲染()函数调用
{this.displayProductSection()}
这就要求this.getLineItems()
这就要求this.getProductPrimaryImage(item.product_id)
这使得AJAX请求到WordPress的API。
Since render can (and likely will) be run repeatedly, this means your request for the image is being created repeatedly.由于渲染可以(并且可能会)重复运行,这意味着您对图像的请求正在重复创建。
Running an AJAX request is not like displaying an image, where you put the src URL in the tag and the browser loads it once.运行一个AJAX请求并不像显示图像,在那里你把src网址在标签和浏览器加载一次。 HTML is parsed and run once, this is requesting it repeatedly.
HTML 被解析并运行一次,这是反复请求它。
A better pattern would be:更好的模式是:
Sometimes you aren't quite ready to fetch the remote data when the component mounts.有时您还没有准备好在组件安装时获取远程数据。 Maybe it depends on some user input first.
也许这首先取决于一些用户输入。 In that case, you could instead hook into componentDidUpdate.
在这种情况下,您可以改为挂钩 componentDidUpdate。 Check for your condition there, but since this function call also run repeatedly, also check the status and only request it if it hasn't been requested yet.
在那里检查您的条件,但由于此函数调用也会重复运行,因此还要检查状态,并且仅在尚未请求时才请求它。
In either case, notice the separation of concerns.无论哪种情况,请注意关注点的分离。 Your render() function is doing one thing -- displaying.
您的 render() 函数正在做一件事——显示。 It's not kicking off network requests or triggering side effects.
它不会启动网络请求或触发副作用。 Your lifecycle methods (or functions that respond to user input) handle that stuff.
您的生命周期方法(或响应用户输入的函数)处理这些东西。
I really appreciated tmdesigned for giving me proper guidance.我真的很感谢 tmdesigned 给了我适当的指导。 I learned the concept of react components again from this link .
我从这个链接中再次学习了反应组件的概念。
So I solved my problem by chaining the subsequent fetch requests as a callback in setState which is called inside componentDidMount.因此,我通过将后续获取请求链接为 setState 中的回调来解决我的问题,该回调在 componentDidMount 中调用。 Below is my implementation
下面是我的实现
componentDidMount() {
this.focusListener = this.props.navigation.addListener('didFocus', () => {
this.fetchOrderDetails()
});
}
fetchOrderDetails = () => {
const url = `${base_url}/wp-json/wc/v3/orders/${orderId}?consumer_key=${c_key}&consumer_secret=${c_secret}`;
this.setState({ loading: true });
fetch(url).then((response) => response.json())
.then((responseJson) => {
this.setState({
orderData: responseJson,
error: responseJson.code || null,
}, this.fetchOrderStatus())
}).catch((error) => {
this.setState({
error,
loading: false
})
});
}
fetchOrderStatus = () => {
const orderStatusesurl = `${base_url}/wp-json/wc/v3/reports/orders/totals?consumer_key=${c_key}&consumer_secret=${c_secret}`;
fetch(orderStatusesurl).then(response => response.json())
.then(responseJson => {
let orderStatusMap = new Map();
if (Array.isArray(responseJson) && responseJson.length > 0) {
if ('slug' in responseJson[0] && 'name' in responseJson[0]) {
responseJson.forEach(item => {
orderStatusMap.set(item.slug, item.name)
})
}
}
this.setState({
orderStatusOptions: [...orderStatusMap],
orderStatusValue: this.state.orderData.status,
loading: false,
}, this.fetchOrderProductImages())
})
}
fetchOrderProductImages = () => {
this.state.orderData.line_items.forEach((item, index) => {
this.fetchProductPrimaryImage(item.product_id, index)
})
}
fetchProductPrimaryImage = (productId, index) => {
this.setState({ imageLoading: true });
let url = `${base_url}/wp-json/wc/v3/products/${productId}?consumer_key=${c_key}&consumer_secret=${c_secret}`
fetch(url)
.then((response) => response.json())
.then(responseJson => {
if ('images' in responseJson && Array.isArray(responseJson.images) && responseJson.images.length) {
if ('line_items' in this.state.orderData && Array.isArray(this.state.orderData.line_items) && this.state.orderData.line_items.length) {
let modifiedOrderData = this.state.orderData
modifiedOrderData.line_items[index].primary_image_src = responseJson.images[0].src
this.setState({
orderData: modifiedOrderData,
imageLoading: false,
error: responseJson.code || null,
})
}
} else {
this.setState({
imageLoading: false,
error: responseJson.code || null,
});
}
})
.catch((error) => {
this.setState({
error,
imageLoading: false,
})
});
}
getLineItems = () => {
let itemArray = [];
this.state.orderData.line_items.forEach(item => {
itemArray.push(
<View key={item.id} style={{ flex: 1, flexDirection: 'row', backgroundColor: 'white' }}>
<View style={{ flex: 1, justifyContent: "center", alignContent: "center" }}>
<Image source={'primary_image_src' in item?{uri: item.primary_image_src}:null}
style={{ height: 100, width: 100 }} resizeMode='contain' />
</View>
<View style={{ flex: 2, marginTop: 10, marginBottom: 10, justifyContent: "center" }}>
<View style={{ marginLeft: 10 }}>
<Text>{item.name}</Text>
<Text>SKU: {item.sku}</Text>
<Text>Price: {this.getCurrencySymbol()}{item.price.toFixed(2)}</Text>
<Text>Oty: {item.quantity}</Text>
<View>{this.getTMProductOptions(item.meta_data)}</View>
</View>
</View>
</View>
)
})
return itemArray;
}
render() {
if (this.state.loading) {
return (
<View style={{ flex: 1, justifyContent: "center", alignContent: "center", padding: 20 }}>
<ActivityIndicator color='#96588a' size='large' />
</View>
)
}
return (
<ScrollView style={{ flex: 1 }}>
{this.displayOrderDataSection()}
{this.displayProductSection()}
{this.displayPaymentSection()}
{this.displayShippingDetailsSection()}
{this.displayBillingDetailsSection()}
</ScrollView>
);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.