Переменная перехватывает состояние переменной не обновляется после перерисовки - PullRequest
1 голос
/ 09 апреля 2019

В следующем примере у меня есть массив элементов (фруктов), которые я хочу обновить, и использую обновленный массив для выполнения других операций (в данном конкретном случае сохранение обновленного списка).Насколько я понимаю, при повторном отображении состояние будет обновляться ... но это не так ... или существует задержка между обновлением состояния и моим действием.

В функции addFruit я вижу, что 'Peach' немедленно добавляется, но консоль из функции saveFruits по-прежнему показывает состояние fruit, которое остается неизменным.Как я могу обновить это, чтобы использовать немедленно.(И я знаю, что в этом случае я могу передать newFruits переменную saveFruits для обновления, но мне нужно fruits для обновления и в других местах).

Простите меня, потому что это мой миллионный вопрос о реакции асинхронных состояний, но есть кое-что, что просто еще не нажимает на меня.

const { useState } = React;

function ParentComp() {
    const[fruits, setFruits] = useState(['Apple', 'Orange', 'Banana', 'Pomegranate', 'Kiwi'])


   const addFruit = () => {
      let newFruits = Object.assign([], fruits)
      newFruits.push('Peach')
      setFruits(newFruits)
      saveFruits()
   }
   
   const saveFruits = () => {
      console.log('API req to save fruits.', fruits)
   }

   return (
    <div>
    { fruits.map( (fruit, key) => <div key={key}>{fruit}</div> ) }
      <button type="button" onClick={addFruit}>Add Peach</button>
    </div>
   )
}

ReactDOM.render(<ParentComp />, document.getElementById('root'))
<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
  <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>

<div id="root"></div>

Ответы [ 2 ]

5 голосов
/ 09 апреля 2019

Вы можете попробовать использовать useEffect, которое будет давать обновленное состояние всякий раз, когда будет происходить обновление.

useEffect(() => {
    saveFruits();
  }, [fruits]);
1 голос
/ 09 апреля 2019

Это не точно для console.log fruits, поскольку ссылка на fruits все еще относится к fruits, который вы имели до того, как позвонили setFruits.

Если мы console.log newFruits, в котором есть изменения, это будет более точным из того, что происходит.

РЕДАКТИРОВАТЬ: Вероятно, лучше useEffect, как то, что предложил @Atul, хотя.

Иногда помогает визуализировать, как это делается в старых классах React. В старых классах React это эквивалентно (в некоторой степени не совсем, но достаточно близко, чтобы проиллюстрировать суть) (Подробнее: https://reactjs.org/docs/hooks-state.html)

class ParentComp extends React.Component {
  constructor() {
    super();
    this.state = {
      fruits: ['Apple', 'Orange', 'Banana', 'Pomegranate', 'Kiwi']
    };
  }

  addFruit = () => {
    let newFruits = Object.assign([], this.state.fruits);
    newFruits.push('Peach')
    this.setFruits(newFruits)
    this.saveFruits();
  }

  setFruits = (fruits) => {
    this.setState({
      fruits
    });
  }

  saveFruits = () => {
    console.log(this.state.fruits);
  }

  render() {
    return ( 
        <div> 
         {this.state.fruits.map((fruit, key) => {
          return (<div key={key}>{fruit}</div>) })} 
          <button type="button" onClick={this.addFruit}>Add Peach</button>
        </div>
    );
  }
}
ReactDOM.render(<ParentComp /> , document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

<div id="root"></div>

У нас та же проблема, что и выше, но она может быть немного яснее. SetState для fruits вызывается, но console.log происходит до того, как произойдет изменение состояния / рендеринга, поэтому this.state.fruits все еще ссылается на то, что было в состоянии ранее.

Я настоятельно рекомендую прочитать React hooks: не магия, просто массивы , чтобы лучше понять, что происходит за кулисами крючков. Это многое объясняет.

...