Почему getDerivedStateFromProps вызывается после setState?
React представил новый статический метод getDerivedStateFromProps(props, state)
, который вызывается перед каждым методом рендеринга, но почему? Позвонить ему после смены опоры имеет смысл для меня, но после setState
это не так, может быть, я что-то упустил.
Я создавал компонент datePicker
в соответствии с требованиями моей компании, в компоненте дата контролируется с опоры. У меня есть следующее состояние в компоненте.
selectedDate: number;
selectedMonth: number;
selectedYear: number;
currentMonth: number;
currentYear: number;
view: string;
selected представляет выбранную дату, которая получена из подпорки даты, а currentMonth
и currentYear
представляют месяц и год в текущем представлении календаря.
Если date
из пропеллера изменяет selected*
, currentMonth
и currentYear
должны быть изменены соответственно. Для этого я использую getDerivedStateFromProps
, но, скажем, пользователь нажимает на название месяца, которое переключит представление календаря на месяц (вместо того, чтобы будет отображаться название месяца), функция обновляет currentMonth
для этого с помощью setState, но date: реквизит тот же, что и раньше (содержащий предыдущий месяц), который должен, но вызывается getDerivedStateFromProps
и currentMonth снова такой же, как и раньше, вместо изменения.
Хорошо, я создал дополнительную переменную в state
, чтобы отслеживать, вызван ли getDerivedStateFromProps
из-за setState
, но я не думаю, что это правильный путь.
Либо я делаю что-то не так, либо что-то пропускаю, либо getDerivedStateFromProps
не следует вызывать после setState
. Вероятно, я делаю что-то не так.
Ответы
Ответ 1
Я сделал что-то вроде этого
constructor(props) {
super(props);
this.state = {
expanded: props.expanded,
ownUpdate: false
}
}
static getDerivedStateFromProps(props, state) {
if (state.ownUpdate) {
return {
expanded: state.expanded,
ownUpdate: false
};
} else if (props.expanded !== state.expanded) {
return {
expanded: props.expanded
};
}
return null;
}
toggle() {
this.props.onAftePress(this.state.expanded, this.props.index);
this.setState({
expanded: !this.state.expanded,
ownUpdate: true
})
}
Ответ 2
Я также получил эту проблему. Поэтому я установил другую переменную для проверки того, что реквизит получен впервые.
this.state={flag:true}
В getderivedstateromprops
static getderivedstatefromprops(props, state){
if(props.<*propName*> && flag){
return({ props.<*propName*>, flag:false})
}
}
если вы хотите использовать несколько значений реквизита, вам необходимо соответственно установить операторы if (или любую другую логику).
Ответ 3
Хук getDerivedStateFromProps
работает при получении новых реквизитов, setState и forceUpdate.
В версии 16.3
React не влияет на getDerivedStateFromProps
всякий раз, когда используется setState
. Но они улучшили его в версии, начиная с 16.4
, поэтому всякий раз, когда вызывается setState
, подключается getDerivedStateFromProps
.
Вот извлеченное изображение из Реагирует на диаграмму жизненного цикла:
16.3
^ 16,4
Итак, вам решать, когда подключить getDerivedStateFromProps
, правильно проверяя реквизиты и состояния. Вот пример:
static getDerivedStateFromProps (props, state) {
// check your condition when it should run?
if(props.currentMonth != state.currentMonth) {
return {
currentMonth: state.currentMonth
}
}
// otherwise, don't do anything
else {
return null
}
}
Ответ 4
у вас есть ответ на ваш вопрос сам. msgstr "который вызывается перед каждым методом рендеринга". Всякий раз, когда вы делаете setState
метод render
.
Я бы посоветовал вам поднять переменные состояния currentMonth
и currentYear
в родительский компонент и передать их как prop вместе с другими тремя. Вы также можете передать обработчик изменений как реквизит и вызвать его от ребенка.
при начальном render
- currentMonth
и currentYear
могут иметь значение null
, чтобы вы могли иметь логику для отображения материала по умолчанию. Когда кто-то changeHandler
название месяца, вы можете вызвать changeHandler
из parent, который пропустит новую реквизит. Теперь в getderivedstatefromprops
вас больше нет currentMonth
и currentYear
как 'null', поэтому вы знаете, что месяц изменился.