Почему React Hooks нельзя вызывать внутри циклов или вложенных функций? - PullRequest
0 голосов
/ 23 декабря 2018

Документация React Hooks говорит, чтобы не вызывал Hooks внутри циклов, условий или вложенных функций.

Я понял, что порядок выполнения важен, поэтому React можетзнать, какое состояние соответствует какому вызову useState.Учитывая это, очевидно, что ловушка не может быть вызвана внутри условия.

Но я не вижу, в чем проблема, если мы вызываем useState внутри цикла, где число итераций не меняетсявремя.Вот пример:

const App = () => {
  const inputs = [];

  for(let i = 0; i < 10; i++) {
    inputs[i] = useState('name' + i);
  }

  return inputs.map(([value, setValue], index) => (
    <div key={index}> 
      <input value={value} onChange={e => setValue(e.target.value)} />
    </div>
  ));
}

export default App;

Есть ли проблема с этим кодом выше?И в чем проблема вызова useState внутри вложенной функции, если эта функция вызывается при каждом рендеринге?

1 Ответ

0 голосов
/ 23 декабря 2018

Ссылка указывает действительную причину,

Следуя этому правилу, вы гарантируете, что хуки вызываются в одном и том же порядке каждый раз при визуализации компонента.Это то, что позволяет React правильно сохранять состояние хуков между несколькими вызовами useState и useEffect.

и предоставляет пример , показывающий, почему это важно.

Циклы, условия и вложенные функции являются общими местами, где порядок выполнения ловушек может быть нарушен.Если разработчик уверен, что цикл и т. Д. Оправдан и гарантирует порядок, то проблем нет.

Фактически цикл будет считаться действительным пользовательский хук , если он был извлечен в функцию, правило линтера может быть отключено при необходимости ( demo ):

// eslint-disable-next-line react-hooks/rules-of-hooks
const useInputs = n => [...Array(n)].map((_, i) => useState('name' + i));

Приведенный выше пример не вызовет проблем, но цикл не обязательно оправдан;это может быть одно состояние массива:

const App = () => {
  const [inputs, setInputs] = useState(Array(10).fill(''));
  const setInput = (i, v) => {
    setInputs(Object.assign([...inputs], { [i]: v }));
  };

  return inputs.map((v, i) => (
    <div key={i}> 
      <input value={v} onChange={e => setInput(i, e.target.value)} />
    </div>
  ));
}
...