В чем разница между React setState и Hooks setState? - PullRequest
0 голосов
/ 03 мая 2020

разница между -

this.setState({value: 'xyz', name: 'john', color: 'orange'}) 

против

setValue('xyz'); 
setName('john');
setColor('orange');

работают ли крюки / используются синхронно? И когда он начинает фактический рендеринг после первого setValue или в состоянии setColor?

Я также хотел, как это работает под капотом?

Ответы [ 3 ]

1 голос
/ 03 мая 2020

1. За сценой хуки хранятся как список ссылок

https://medium.com/flatiron-labs/breaking-the-rules-of-react-hooks-9e892636641e

https://github.com/facebook/react/blob/9f395904c6033598ba8bf47f5497fd6e5077c16d/packages/react-reconciler/src/ReactFiberHooks.js

Хуки хранятся в виде связанного списка в поле memoizedState волокна. Текущий список подключений - это список, который принадлежит текущему волокну. Список подключений в процессе выполнения - это новый список, который будет добавлен в волокно в процессе выполнения.

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

Таким образом, в случае множественных хуков useState отличается от компонента класса, состояние которого обновляется или выполняется вместе только в одном объекте состояния каждый раз изменяющееся состояние вызывает повторное рендеринг. Хук выполняется отдельно, и замена одного хука не вызовет рендеринга компонента немедленно, это зависит от алгоритма ядра реагирующего волокна.

И, согласно статье выше, каждый рендер создает новый список, связанный с хуком, поэтому hooks должны вызываться в одном и том же порядке для каждого рендера.

Согласно документу React: https://reactjs.org/docs/hooks-rules.html#explanation

... это то, что React полагается на порядок , в котором вызываются хуки.

Если порядок первого и второго рендеров различен, это может привести к ошибке.

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

 const [value, setValue] = useState('xyz');
 const [name, setName] = useState('John');
 const [color,setColor] = useState('Orange')

Затем при реакции будет создан список ссылок для перехвата, а головной узел - это перехватчик setValue, следующим узлом будет setName, и следующий узел будет setColor. И когда setValue('abc') выполнено, реагирует на извлечение головного узла из старого связанного списка, изменение его значения и обращение к следующему его узлу для создания нового связного списка. И если эта строка setName('Bill') будет выполнена следующей, тогда ответ будет делать то же самое, что и выше.

Но когда перезапуск компонента будет запущен? На самом деле, я не уверен, но мы могли бы использовать пример, как показано ниже.

case test1

Внутри функции handleClick, когда выполняется setCount(count + 1), реагировать не будет немедленно выполнять рендеринг компонента, а при выполнении следующей строки setValue(value + count) count все еще относится к старому состоянию. При щелчке 5 раз этот компонент отображается полностью 6 раз.

case test2

В этом случае второе установленное состояние setValue(value + count) запускается через 3 секунды после setCount(count + 1) выполнен. В результате, когда setCount(count + 1) выполняется, компонент рендерит немедленно, через 3 секунды после выполнения setValue(value + count), компонент рендерит снова, но состояние count все еще ссылается на старое состояние. При щелчке 5 раз этот компонент рендерится полностью 11 раз.

Итак, это зависит от алгоритма ядра реагирующего волокна.

Вы можете попробовать следующий код:

case test1

const {useState} = React;

const App=()=> {
  console.log("render App")
  const [count, setCount] = useState(0);
  const [value, setValue] = useState('xyz');
  
  //console.log(value)
  if(count> 5)  //Before count >5 , the order of hooks is : 1.setCount, 2.setValue, 3.setColor , when count is above 5, then change the order of hooks as : 1.setCount, 2.setValue, 3.setName, 4.setColor
  {
    const [name, setName] = useState('John');
  }
  
  const [color,setColor] = useState('Orange')
 
  function handleClick(e) {
    setCount(count + 1)
    setValue(value + count)
    //setTimeout(()=>setValue(value + count),3000)
    
  }
 

  return (
    <div>
      <p>You clicked {count} times, when above 5 times, this function would crash, because order of hooks is changed</p>
      <p>And the 'value' is : {value}, and you might find value didn't plus the new state of count, but old state of count</p>
      <button onClick={handleClick}>
        Click me
      </button>
    </div>
  );
}



ReactDOM.render(
  <App/>,
  document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react"></div>

case test2

const {useState} = React;

const App=()=> {
  console.log("render App")
  const [count, setCount] = useState(0);
  const [value, setValue] = useState('xyz');
  
  //console.log(value)
  if(count> 5)  //Before count >5 , the order of hooks is : 1.setCount, 2.setValue, 3.setColor , when count is above 5, then change the order of hooks as : 1.setCount, 2.setValue, 3.setName, 4.setColor
  {
    const [name, setName] = useState('John');
  }
  
  const [color,setColor] = useState('Orange')
 
  function handleClick(e) {
    setCount(count + 1)
    //setValue(value + count)
    setTimeout(()=>setValue(value + count),3000)        
  }
 

  return (
    <div>
      <p>You clicked {count} times, when above 5 times, this function would crash, because order of hooks is changed</p>
      <p>And the 'value' is : {value}, and you might find value didn't plus the new state of count, but old state of count</p>
      <button onClick={handleClick}>
        Click me
      </button>
    </div>
  );
}



ReactDOM.render(
  <App/>,
  document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react"></div>
1 голос
/ 03 мая 2020

setState объединяет предыдущее состояние с новым, это означает, что вам не нужно передавать объект полного состояния каждый раз, когда вы хотите изменить какую-либо часть состояния.

React обновит данные свойства и не буду касаться остальных.

Программа обновления useState перезаписывает предыдущее состояние новым, и оно не выполняет слияние.

Это просто замена вместо слияния.

0 голосов
/ 03 мая 2020

В вашем примере, с перехватом, ваш компонент рендерится три раза. но вы можете написать:

const [data, setData] = useState({value: '', name: '', color: ''});

И установить их вместе:

setData({...data, value: 'xyz', name: 'john', color: 'red'} );

Теперь нет никакой разницы.

Как правило, единственный аргумент для useState() Крюк это начальное состояние. В отличие от классов, состояние не обязательно должно быть объектом. Мы можем сохранить число или строку, если это все, что нам нужно. В отличие от метода setState, найденного в компонентах класса, useState не объединяет объекты обновления автоматически.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...