我正在为工作中的一个项目学习 React,目前在掌握异步模型方面确实遇到了困难。
这是我正在开发的组件:
const Customers = () => {
const [logos, setLogos] = useState([]);
const [customers, setCustomers] = useState([]);
const [titlePrompt, setTitlePrompt] = useState([]);
const navigate = useNavigate();
useEffect(() => {
// create a customer client object
const client = new Client();
// query for the customer list and save name and token
if (customers.length === 0) {
client.get_customers().then((res) => {
const customer_info = res.map(customer => {
return {
'name': customer.customer_name,
'token': customer.mqtt_customer_token
}
});
setCustomers(customer_info);
});
}
if (customers.length > 0) {
const fetched_logos = [];
for (let i = 0; i < customers.length; i++) {
client.get_site_by_type(customers[i].token, 1).then((res) => {
const new_logo = {
[customers[i].name]: res.logo
};
fetched_logos.push(new_logo);
});
}
setLogos(fetched_logos);
}
setTitlePrompt("Select A Customer Shown Below");
}, [customers, logos]);
/**
* button handler to transition to a dataframe view of the chosen customer via token
* @param {defining} token
*/
const onButtonClick = (token) => {
navigate('/dataframe', { state: { token } });
};
return (
<div className={'mainContainer'}>
<div className={'contentContainer'}>
<div className={'titleContainer'}>
<div>{titlePrompt}</div>
</div>
<br/>
<ImageList cols={4}>
{customers.map(customer => (
<ImageListItem key={customer.name}>
<img alt={customer.name} src={`data:image/png;base64,${logos[customer.name]}`}></img>
</ImageListItem>
))}
</ImageList>
</div>
</div>
);
};
export default Customers;
我想做的是获取客户信息,例如名称和徽标,并将其显示在 ImageList 中。
问题是,首先我必须从一个数据库中获取每个客户的名称和令牌(用于后续 API 调用),然后我需要一一获取徽标,因为它们都驻留在特定的客户数据库中。我想仅使用 img 组件的替代文本来渲染组件,然后在图像进入时填充它们。我只是不知道如何在 useEffect 中正确同步它。我也不知道使用 if 语句来控制后续 useEffect 调用期间执行的内容是否正确,或者只是黑客行为。
我尝试链接 .then 但 setState 调用是异步的,因此会导致竞争条件并且不起作用。
感谢您的阅读。
编辑:
这是一个代码片段,显示了我尝试链接 .then:
client.get_customers().then((res) => {
const customer_info = res.map(customer => {
return {
'name': customer.customer_name,
'token': customer.mqtt_customer_token
}
});
setCustomers(customer_info);
}).then(() => {
for (let i = 0; i < customers.length; i++) {
client.get_site_by_type(customers[i].token, 1).then((res) => {
const new_logo = {
[customers[i].name]: res[0].logo
}
setLogos([...logos, new_logo]);
});
}
});
有两个问题,一是调用set函数后状态变量不会立即更新。 更好的是使用包含接收到的数据的变量(这里,我返回 customer_info,以便可以在
then
中使用它,而不是调用 setCustomers 然后期望 const 客户已更新,但事实并非如此) .
第二个问题是你需要使用promise.all或类似的来正确同步它。
未经测试的说明性代码:
client.get_customers().then((res) => {
const customer_info = res.map(customer => {
return {
'name': customer.customer_name,
'token': customer.mqtt_customer_token
}
});
setCustomers(customer_info);
return customer_info;
}).then((customer_info) => {
const promises = customer_info.map(customer =>
client.get_site_by_type(customer.token, 1).then((res) => {
const new_logo = {
[customer.name]: res[0].logo
}
return new_logo;
})
);
Promise.all(promises).then(logos => setLogos(logos));
});