我正在开发一个连接到 firebase 数据库的 React 应用程序。应用程序的一部分读入属于当前用户的 Items 列表,然后为每个读入一个 config 对象,最后更新状态中的项。我在让它工作时遇到问题 - 我似乎一直在工作
我的组件是:
const Dashboard = () => {
const authUser = useContext(AuthUserContext);
const firebase = useContext(FirebaseContext);
const [error, setError] = useState<string|null>(null);
const [firebaseToken, setFirebaseToken] = useState<string|null>(null);
const [items, setItems] = useState<Array<ItemModel>>([]);
// On first render, get all Items
useEffect(() => {
if(!authUser) return;
if(!firebase) return;
let userId = authUser.id;
const getItems = () => {
firebase.doGetIdToken()
.then((token) => {
// Save token so it can be passed down
setFirebaseToken(token);
url = "items/" + userId;
Client.getData(url, token)
.then((itemResults:Array<ItemModel>) => {
// Get config for each Item
// Set up an empty array to hold the new data
const itemResultsWithConfigs:Array<ItemModel> = []
// Now get the config for each item
itemResults.forEach((item:ItemModel) => {
// Get config for this Item
url = "/items/config/" + item.id;
Client.getData(url, token)
.then((newConfig:ConfigModel) => {
let newItem:ItemModel = {
...item,
config: newConfig
}
// Add full item to list & update list
itemResultsWithConfigs.push(newItem);
})
})
setItems(itemResultsWithConfigs);
})
});
})
})
.catch(() => setError("Unable to connect to database"))
}
getItems();
}, [authUser, firebase])
return (
<>
<ul>
{
items.map((item:ItemModel) => {
return <li key={item.id}>{item.name}</li>
})
}
</ul>
</>
);
}
export default Dashboard;
Client.getData 是:
async function getData(path:string, token:string) {
const object:AxiosRequestConfig = {
...obj,
method: 'GET',
headers: {
...obj.headers,
'Authorization': `Bearer ${token}`,
},
};
try {
const response:AxiosResponse = await axios.get(`${baseUrl}${path}`, object);
checkStatus(response);
const parsedResult = parseJSON(response);
return parsedResult;
} catch (error) {
throw error;
}
}
问题是异步函数 (getData) 在不同时间返回,因此有时会覆盖项目数组。目前这只是渲染一两个项目,而不是我知道应该在那里的 3 个。
我该如何处理?
答案 0 :(得分:2)
由于 itemResultsWithConfig 是异步派生的,一个好主意是使用 Promise.all
映射并等待所有承诺解析
const getItems = () => {
firebase.doGetIdToken()
.then((token) => {
// Save token so it can be passed down
setFirebaseToken(token);
url = "items/" + userId;
Client.getData(url, token)
.then((itemResults:Array<ItemModel>) => {
// Get config for each Item
// Set up an empty array to hold the new data
// Now get the config for each item
let promises = itemResults.map((item:ItemModel) => {
// Get config for this Item
url = "/items/config/" + item.id;
return Client.getData(url, token)
.then((newConfig:ConfigModel) => {
let newItem:ItemModel = {
...item,
config: newConfig
}
return newItem;
})
})
Promise.all(promises).then((itemResultsWithConfigs:Array<ItemModel>) => setItems(itemResultsWithConfigs))
})
});
})