Назначение объектов в 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} />
        );
    });
}
Другие вопросы по тегам