Есть потенциальная проблема с прохождением объектных литералов для настройки, как ниже,
this.setState({someKey: someValue})
Фрагмент кода ниже иллюстрирует потенциальную проблему. Мы добавили STATSTATE три раза в краткую последовательность и добавили обратный вызов для регистрации обновленного состояния в консоль после каждого вызова.
state = { counter: 0 } incrementCounter = () => { this.setState( { counter: this.state.counter + 1 }, () => console.log() ) } componentDidMount = () => { incrementCounter() incrementCounter() incrementCounter() } //output {counter: 1} {counter: 1} {counter: 1}
Возможно, вы ожидали, что вывод будет:
{counter: 1} {counter: 2} {counter: 3}
Есть две причины непреднамеренного вывода:
- Асинхронные обновления
- Полученные обновления
Реагирует Asynchronous Update можно лучше описать с фрагментом кода ниже:
state = { counter: 0 } incrementCounter = () => { this.setState( { counter: this.state.counter + 1 } ) console.log(this.state.counter) //this will always return the state before the new state above is reflected in state } incrementCounter() // 0 incrementCounter() // 1
Вместо регистрации 1, первоначальный вызов для увеличения CountCounter Logs 0, вторые журналы вызовов 1 вместо 2, и она продолжается так.
Полученные обновления описаны в официальных документах с образцом кода ниже,
Object.assign( previousState, {quantity: state.quantity + 1}, {quantity: state.quantity + 1}, ... )
Поэтому наш начальный фрагмент кода фактически превращается в что-то подобное,
Object.assign( previousState, {counter: state.counter + 1}, {counter: state.counter + 1}, {counter: state.counter + 1})
Итак, как вы избегаете этих потенциальных проблем, передавая функцию для настройки, а не объекта.
incrementCounter = () => { this.setState((presentState) => ( Object.assign({}, presentState, { counter: presentState.counter + 1 }) )) } componentDidMount = () => { incrementCounter() incrementCounter() incrementCounter() } //output {counter: 3} {counter: 3} {counter: 3}
Таким образом, метод setState всегда будет передавать современное состояние функции. Обратите внимание, что мы используем Object.Ascign, чтобы создать новый объект из Nownstate.
Обратите внимание, что вы не должны делать это,
this.setState((presentState) => { presentState.counter+= 1 return presentState })
Хотя вышеизложенное приведет к тому, что обновление до состояния и повторного визуализации фрагмент ниже не будет, из-за неглубокого сравнения реагирования.
state = { someProp: { counter: 0 } } this.setState((presentState) => { presentState.someProp.current += 1 return presentState })
Это все еще безопасно пропустить SetState объект литерала, когда новое состояние не зависит от старого состояния, но вместо этого передает его функции, – это лучший шаблон. Если вы знакомы с Redux, это похоже на редукторы Redux.
Возможно, вы заметили мое использование функций стрелки с помощью метода risrementCounter. Это предлагается ES7 Синтаксис инициализатора свойств , вы можете использовать его сейчас с бабелом Плагин. .
Ваше здоровье.
Оригинал: “https://dev.to/promhize/better-reactjs-patterns-setstate-pitfalls-aj9”