Невозможно установить состояние после выполнения componentDidMount

У меня есть следующая переменная state и метод componentDidMount на моем компоненте:

  state = {
    categorized_items: []
  }
  componentDidMount() {
    this.props.fetchItems()
    // I'm trying to do the following
    console.info('uncat_items: ', this.props.uncat_items)
    this.setState({categorized_items: this.props.uncat_items})
  }
  render () {....}

  function mapStateToProps({ items_reducer }) {
    return {
     uncat_items: items_reducer.uncat_items
    }
  }

Метод действия this.props.fetchItems() извлекает ряд элементов и просто обновляет uncat_items в хранилище redux (я без проблем вижу ожидаемые значения для переменной this.props.uncat_items в методах render / other). Однако то, что мне нужно сделать в этом конкретном случае, - это сразу после того, как метод fetchItems будет выполнен и он обновит uncat_items в магазине, мне нужно вызвать setState и обновить categorized_items в состоянии с uncat_items. Я знаю, что вызывать this.setState таким образом в методе componentDidMount неправильно, но я не знаю, как это сделать. Как видите, я попытался распечатать this.props.uncat_items, но он вернул пустой массив, хотя он выполнил метод действия и правильно обновил в редукторе. Может кто-нибудь дать мне идею, как это сделать правильно? По сути, после выполнения componentDidMount установите состояние с определенной переменной из обновленного хранилища redux.

Ваш console.info() выдал пустой массив, потому что это не асинхронный вызов; он был выполнен до того, как fetchItems() вернул какие-либо данные. (Если fetchItems() возвращает обещание, вы можете легко это исправить.)

Andy Taton 18.10.2018 22:32

почему бы просто не использовать this.props.uncat_items непосредственно в функции рендеринга (или там, где вы хотите использовать this.state.categorized_items)?

Łukasz Godziejewski 18.10.2018 22:33

Если вам не нужно редактировать отдельную копию данных, лучше всего не копировать ваши реквизиты в ваше состояние. Вместо этого вы можете использовать условный рендеринг в функции render, например return this.props.uncat_items.length > 0 ? <ul>...</ul> : <p>No items</p>

Geoffrey H 18.10.2018 22:57
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
3
409
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы можете использовать метод жизненного цикла componentDidUpdate. Похоже, что когда ваш компонент монтирует ваш магазин, он все еще может содержать значение по умолчанию для этой части состояния. Затем он правильно обновляется в хранилище redux, как вы упомянули, но состояние компонента не обновляется.

Чтобы обновить состояние компонента после того, как компонент получил новые реквизиты:

componentDidUpdate(prevProps){
  // compare prevProps to current props and update
  if (this.props.uncat_items !== prevProps.uncat_items) {
    this.setState({categorized_items: this.props.uncat_items})
    }
  }

Как упоминалось в комментариях, использование props непосредственно в методе рендеринга является более идеальным решением, поскольку вы не хотите, чтобы ваш компонент без необходимости повторно рендерил.

Я бы не сказал, что это оптимальное решение, так как это вызовет еще один повторный рендеринг компонента.

Łukasz Godziejewski 18.10.2018 23:34

Да, в идеале опору следует использовать напрямую, как указано в документации. Хотя полезно продемонстрировать оператору, почему свойство и состояние не соответствуют его ожиданиям на данном этапе жизненного цикла компонента.

kasho 19.10.2018 01:19
Ответ принят как подходящий

Проблема в вашем коде заключается в том, что вы вызываете асинхронное действие (this.props.fetchItems()), а затем немедленно вызываете this.setState(), что происходит до завершения запроса fetchItems (таким образом, до заполнения props.uncat_items).

Предполагая, что вы используете новейшую версию React, в зависимости от конкретного варианта использования вы можете:

1) Отбросьте состояние и просто используйте this.props.uncat_items напрямую в функции рендеринга.

2) Используйте static getDerivedStateFromProps для обновления состояния из-за новых свойств.

тем не мение, как упоминалось в документы, на самом деле не рекомендуется, поскольку в большинстве случаев можно обрабатывать по-другому (например, переключаясь на управляемый компонент, как указано в решении № 1). Более подробное описание можно найти в эта статья, который также упоминается в документации.

Другие вопросы по теме