Что именно componentWillReceiveProps и getDerivedStateFromProps - тонкий вопрос для меня. Потому что я столкнулся с проблемой при использовании getDerivedStateFromProps:
// Component
state = {
myState: []
}
// Using this method works fine:
componentWillReceiveProps(nextProps) {
this.setState({
myState: nextProps.myPropsState
})
}
// But using this method will cause the checkboxes to be readonly:
static getDerivedStateFromProps(nextProps,prevProps) {
const { myPropsState: myState } = nextProps
return {
myState
}
}
// And here's checkbox
<input type = "checkbox" id = {`someid`}
onChange = {(e) => this.handleMethod(e, comp.myState)}
checked = {myState.indexOf(comp.myState) > -1} />
Версия React: 16.4.1
это не должно иметь значения здесь, однако, имя параметра может быть любым, но я только что написал для сравнения, получит реквизиты. Кроме того, я здесь, чтобы узнать, почему флажки доступны только для чтения, когда я использую производное состояние?
Как это помогает сравнивать их, называя свои параметры чем-то, что они не представляют? Также Безоговорочное обновление состояния из реквизита считается анти-паттерном.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


getDerivedStateFromProps не является прямой альтернативой componentWillReceiveProps исключительно из-за того, что он вызывается после каждого обновления, будь то изменение состояния, изменение свойств или повторный рендеринг родительского объекта.
Однако в любом случае простое возвращение состояния из getDerivedStateFromProps - неправильный путь, вам необходимо сравнить состояние и свойства перед возвратом значения. В противном случае с каждым обновлением состояние сбрасывается до props, и цикл продолжается.
Согласно документы
getDerivedStateFromPropsis invoked right before calling the render method, both on the initial mount and on subsequent updates. It should return an object to update the state, ornullto update nothing.This method exists for rare use cases where the state depends on changes in props over time. For example, it might be handy for implementing a
<Transition>component that compares its previous and next children to decide which of them to animate in and out.Deriving state leads to verbose code and makes your components difficult to think about. Make sure you’re familiar with simpler alternatives:
If you need to perform a side effect (for example, data fetching or an animation) in response to a change in props, use
componentDidUpdatelifecycle instead.If you want to re-compute some data only when a prop changes, use a
memoizationhelper instead.If you want to “reset” some state when a prop changes, consider either making a component
fully controlledorfully uncontrolled with a key instead.
P.S. Обратите внимание, что аргументы для getDerivedStateFromProps - это props и state, а не nextProps и prevProps.
Чтобы получить более подробную информацию,
Чтобы вносить изменения на основе изменения реквизита, нам нужно сохранить prevPropsState в состоянии, чтобы обнаруживать изменения. Типичная реализация будет выглядеть так:
static getDerivedStateFromProps(props, state) {
// Note we need to store prevPropsState to detect changes.
if (
props.myPropsState !== state.prevPropsState
) {
return {
prevPropsState: state.myState,
myState: props.myPropsState
};
}
return null;
}
Спасибо за Ваш ответ. Но все же я столкнулся с той же проблемой.
@BhojendraNepal Прочтите это официальное сообщение в блоге о том, как справляться с такими ситуациями. Использование getDerivedStateFromProps, вероятно, вообще не лучший выбор для вашей проблемы.
@BhojendraNepal, если myState является массивом, тогда прямая проверка props.myPropsState !== state.prevPropsState не удастся, вам нужно либо глубоко сравнить массив, либо использовать неизменяемый список
@ShubhamKhatri Следует использовать новый key (или id, если повторно инициализировать компонент дорого), переданный от родителя, чтобы разрешить сброс состояния от родителя путем передачи новых свойств. Это все описывается здесь. Мне не кажется, что глубокое сравнение объектов перед каждым рендером - хорошее решение.
@trixn Лучший способ справиться с такими случаями - это мемоизация и использование неизменяемых списков объектов. Я дополню ответ более подробной информацией, когда у меня будет больше времени ночью
Я не хочу использовать мемоизацию. Есть ли другое решение, кроме производного состояния?
@BhojendraNepal, почему вы не хотите использовать мемоизацию.
@Shubham Khatri Лучший способ повторно вычислить состояние - это запоминание. Однако в этом примере ничего не вычисляется. Итак, лучший и официально рекомендуемый способ - использовать key или id для сигнализации сброса. Или, конечно, вы можете просто сделать это полностью управляемым и позволить родителю обрабатывать обновления (наиболее эффективно).
На самом деле, мне нужно установить myState не из реквизита, а вы устанавливаете состояние по-другому. В этом случае ответ на проблему сильно отличается. На ваш ответ я правильно сравниваю массив. Я могу подумать, что мне не следует использовать производное состояние. и нужно найти какое-то решение.
В этом примере ничего не вычисляется, потому что всякий раз, когда компонент будет получать реквизиты, я всегда этого хочу, однако попробовал ваше предложение, возвращающее значение null, но не помогло.
@BhojendraNepal Да, все в порядке, я не хотел сказать, что ты должен что-то вычислить. Но просто повторюсь: если вы хотите (частично) сбросить состояние дочернего элемента, передав новые реквизиты, вы должны либо использовать key, либо id, которые вы передаете, и сравнивать, изменилось ли оно, или полностью поднять состояние до родительского, чтобы позволить он обрабатывает изменения. Это очень подробно описано в это официальное сообщение в блоге, повторюсь еще раз. Не знаю, почему вы отказываетесь его читать.
Из ответных документов:
Note that this method is fired on every render, regardless of the cause. This is in contrast to
UNSAFE_componentWillReceiveProps, which only fires when the parent causes a re-render and not as a result of a localsetState.
Вы эффективно переопределяете свое состояние с помощью текущих свойств каждый раз после вызова setState(). Поэтому, когда вы устанавливаете флажок, вызывается (e) => this.handleMethod(e, comp.myState), который предполагает вызовы setState() для обновления отмеченного состояния флажка. Но после этого будет вызван getDerivedStateFromProps() (перед рендерингом), который отменяет это изменение. Вот почему Безоговорочное обновление состояния из реквизита считается анти-паттерном.
Наконец, я решил свою проблему. Отладка была мучительной:
// Child Component
// instead of this
// this.props.onMyDisptach([...myPropsState])
// dispatching true value since myPropsState contains only numbers
this.props.onMyDispatch([...myPropsState, true])
Это потому, что у меня есть два условия: 1) при изменении флажка (компонент) 2) при нажатии кнопки сброса (дочерний компонент)
Мне нужно было сбросить состояния при нажатии кнопки сброса. Итак, при отправке состояния реквизитам для кнопки сброса я использовал логическое значение, чтобы знать, что это изменение от сброса. Вы можете использовать все, что захотите, но вам нужно это отслеживать.
Теперь, здесь, в компоненте, я нашел некоторые подсказки о различиях между componentWillReceiveProps и getDerivedStateFromProps после отладки вывода консоли.
// Component
static getDerivedStateFromProps(props, state) {
const { myPropsState: myState } = props
// if reset button is pressed
const true_myState = myState.some(id=>id===true)
// need to remove true value in the store
const filtered_myState = myState.filter(id=>id!==true)
if (true_myState) {
// we need to dispatch the changes to apply on its child component
// before we return the correct state
props.onMyDispatch([...filtered_myState])
return {
myState: filtered_myState
}
}
// obviously, we need to return null if no condition matches
return null
}
Вот что я нашел результаты вывода консоли:
getDerivedStateFromProps регистрирует сразу же при изменении свойств
componentWillReceiveProps регистрирует только после того, как дочерний элемент распространяет изменения реквизита
getDerivedStateFromProps не отвечает на изменения реквизита (я имел в виду изменения отправки, как в примере кода)
componentWillReceiveProps реагирует на изменения реквизита
Таким образом, нам нужно было внести изменения в дочерний компонент при использовании getDerivedStateFromProps.
Процесс вставки истинного значения в состояние, которое мне нужно, потому что getDerivedStateFromProps обрабатывает все изменения, в отличие от componentWillReceiveProps, обрабатывает только дочерний компонент, отправляющий изменения в реквизиты.
Кстати, вы можете использовать настраиваемое свойство, чтобы проверить, изменилось ли оно, и обновить значение, если getDerivedStateFromProps, но по какой-то причине мне нужно настроить эту технику.
В моих формулировках может быть некоторая путаница, но я надеюсь, что вы ее поймете.
Элементы в списках обычно должны быть одного типа. Также вы просматриваете весь список, чтобы найти это значение. Обратите внимание, что вы делаете это на каждом рендере, хотя, вероятно, в 99% случаев внутри boolean нет. Почему бы просто не передать еще одну опору вместе со сбросом, который вы проверяете, изменился ли он? Например. счетчик с автоинкрементом, как это предлагается в ответном сообщении в блоге? Это будет намного эффективнее, проще и менее подвержено ошибкам. Вы писали, что «getDerivedStateFromProps не реагирует на изменения реквизита». Это неправда. Он реагирует на каждое изменение свойств или состояния.
ах, это немного сбивает с толку других. Я хотел сказать, что использование componentWillReceiveProps не требует отправки, но использование производного требует от меня отправки изменений. и я согласен с вашим предложением, но по какой-то причине я использовал вышеуказанный метод.
Параметрами, переданными в
getDerivedStateFromProps (), являются текущиеpropsиstate, а неnextPropsиprevProps. Он должен возвращать следующее состояние в зависимости от текущего состояния и свойств. Пожалуйста, внимательно прочтите хотя бы документацию.