Назначение объектов в JavaScript
Есть объект product
у которого есть объект manufacturer
как его поле. После получения manufacturers
с моего сервера я переназначаю поле продукта manufacturer
с новыми данными (например, извлеченный производитель имеет дополнительный объект avatar
как свое поле).
async componentDidMount() {
strapi.setToken(this.state.user.jwt);
const products = await strapi.getEntries('products');
products.forEach(async product => {
const manufacturer = await strapi.getEntry('manufacturers', product.manufacturer.id); //fetched manufacturers has additional field "avatar"
Object.assign(product.manufacturer, manufacturer);
});
console.log(products); // product.manufacturer.avatar is not null
this.setState({
products
});
Затем я пытаюсь отобразить аватар в React render().
render() {
if (!this.state.products) return null;
return(
{this.state.products ? this.state.products.map(product => (
// and it says that avatar is null
<img src={product.manufacturer.avatar.url} />
// displays manufacturer with avatar object
{console.log(product.manufacturer)}
// says null!
{console.log(product.manufacturer.avatar)}
))}
)
}
Также, когда я проверяю состояние с помощью React Developer Tools, поле продукта manufacturer
имеет объект avatar
и это не ноль.
ОБНОВЛЕНИЕ: Спасибо Сергею Суслову
strapi.setToken(user.jwt);
const fetchedProducts = await strapi.getEntries('products');
const promices = fetchedProducts.map(async fetchedProduct => {
const manufacturer = await strapi.getEntry('manufacturers', fetchedProduct.manufacturer.id);
const product = { ...fetchedProduct, manufacturer };
return product;
});
Promise.all(promices).then(products =>
this.setState({
products
})
);
2 ответа
Вы назначаете с помощью метода assign, который не изменяет исходный объект, в результате он возвращает новый объект, проверьте это https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign. Вам нужно сделать что-то вроде этого: product = { ...product, производитель: ваше назначение присвоения} Основная причина в том, что ваша функция обратного вызова в foreach является асинхронной, js не ожидает завершения всех вызовов функции foreach, она продолжает работать, используйте асинхронное слово, попробуйте использовать Promise для этого или лучше попробуйте использовать действия для асинхронных запросов, спасибо библиотекарю или сагам.
Это потому, что при первом рендере у вас нет avatar
значение. Эти значения выбираются после первого рендера (componentDidMount
).
Вам нужно добавить тест, чтобы учесть этот первый рендер.
Кроме того, причина, по которой ваш console.log не соответствует, заключается в том, что вы перезаписываете значение продукта, чтобы быть более неизменным, вам следует .map
вместо forEach и вернуть копию вашего продукта вместо изменения существующего.
Как бы я написал это:
constructor(props){
super(props);
this.state = {
products: []
}
}
render() {
return this.state.products.map(product => {
const {
avatar = {}
} = product.manufacturer;
return (
<img src={avatar.url} />
);
});
}