React+AWS Amplify DataStore中如何获取Promise类型的菜品数据?
问题:React中使用AWS Amplify DataStore时关联字段返回Promise无法访问属性
开发React项目时,使用AWS Amplify DataStore查询OrderDish数据后,发现dishItem.Dish是Promise类型,无法直接访问name、price等属性。怀疑是Amplify版本更新导致(教程示例无此问题),尝试过.then()和async/await但未找到正确实现方式。
相关代码
import {Card, Descriptions, Divider, List, Button} from 'antd'; import { useEffect, useState } from 'react'; import {useParams} from 'react-router-dom'; import {DataStore} from '@aws-amplify/datastore'; import {Order, OrderDish, User} from '../../models'; const DetailedOrder = () => { const {id} = useParams(); const [order, setOrder] = useState(null); const [customer, setCustomer] = useState(null); const [dishes, setDishes] = useState([]); useEffect(() => { DataStore.query(Order, id).then(setOrder); }, [id]); useEffect(() => { if(order?.userID) { DataStore.query(User, order.userID).then(setCustomer); } }, [order?.userID]); useEffect(() => { if(!order?.id){ return; } DataStore.query(OrderDish, c => c.orderID.eq(order.id)).then(setDishes); }, [order?.id]) console.log(dishes); return ( <Card title={`Order #${id}` } style={{ margin: 20 }}> <Descriptions bordered column={{ lg:1, md:1, sm:1 }}> <Descriptions.Item label="Customer">{customer?.name}</Descriptions.Item> <Descriptions.Item label="Customer Address">{customer?.address}</Descriptions.Item> </Descriptions> <Divider /> <List dataSource={dishes} renderItem={(dishItem) => ( <List.Item> <div style={{fontWeight: 'bold'}}>{dishItem.Dish.name} x{dishItem.quantity}</div> <div>${dishItem.Dish.price}</div> </List.Item> )}/> <Divider /> <div style={styles.totalSumContainer}> <h2 style={{fontWeight: '400'}}>Total:</h2> <h2 style={styles.totalPrice}>${order?.total?.toFixed(2)}</h2> </div> <Divider /> <div style={styles.buttonsContainer}> <Button block type='danger' size='large' style={styles.button}> Decline Order </Button> <Button block type='primary' size='large' style={styles.button}> Accept Order </Button> </div> <Button block type='primary' size='large'> Ready For Pickup </Button> </Card> ); }; const styles = { totalSumContainer: { flexDirection: 'row', display: 'flex', }, totalPrice: { marginLeft: 'auto', fontWeight: 'bold', }, buttonsContainer: { display: 'flex', paddingBottom: 30, }, button: { marginRight: 10, marginLeft: 10, color: 'white', }, }; export default DetailedOrder;
控制台现象
查询返回的dishes数组中,每个dishItem的Dish字段为Promise对象,无法直接读取属性。
解决方法
方式1:预解析关联数据并存入状态
在查询OrderDish后,逐个解析关联的Dish对象,将完整数据存入状态:
- 修改useEffect中的查询逻辑:
useEffect(() => { if(!order?.id){ return; } const fetchDishes = async () => { const orderDishes = await DataStore.query(OrderDish, c => c.orderID.eq(order.id)); // 批量解析关联的Dish数据 const dishesWithData = await Promise.all( orderDishes.map(async od => ({ orderDish: od, dish: await od.Dish })) ); setDishes(dishesWithData); }; fetchDishes(); }, [order?.id])
- 更新List的渲染逻辑:
<List dataSource={dishes} renderItem={(item) => ( <List.Item> <div style={{fontWeight: 'bold'}}>{item.dish.name} x{item.orderDish.quantity}</div> <div>${item.dish.price}</div> </List.Item> )}/>
方式2:使用DataStore的populate参数(新版本支持)
如果你的Amplify版本支持,可直接在查询时指定加载关联字段:
useEffect(() => { if(!order?.id){ return; } const fetchDishes = async () => { const orderDishes = await DataStore.query(OrderDish, c => c.orderID.eq(order.id), { populate: ['Dish'] } // 直接加载关联的Dish数据 ); setDishes(orderDishes); }; fetchDishes(); }, [order?.id])
此方式下dishItem.Dish会直接解析为Dish对象,原渲染代码无需修改。
方式3:React 18+ 结合Suspense处理异步组件
- 创建异步子组件渲染单个菜品:
const DishItem = async ({ dishItem }) => { const dish = await dishItem.Dish; return ( <List.Item> <div style={{fontWeight: 'bold'}}>{dish.name} x{dishItem.quantity}</div> <div>${dish.price}</div> </List.Item> ); };
- 父组件用Suspense包裹List:
<Suspense fallback={<div>Loading dishes...</div>}> <List dataSource={dishes} renderItem={(dishItem) => <DishItem dishItem={dishItem} />} /> </Suspense>
内容的提问来源于stack exchange,提问作者amgosek
相关产品推荐
相关产品推荐

