Отключение состояния из ловушки React's useState - PullRequest
2 голосов
/ 15 марта 2019

Так ли это, и почему плохая идея изменять состояние из нового хита useState в React? Я не нашел информации по теме.

Рассмотрим следующий код:

const [values, setValues] = useState({})

// doSomething can be called once, or multiple times per render

const doSomething = (name, value) => {
  values[name] = value
  setValues({ ...values })
}

Обратите внимание на мутацию значений. Поскольку doSomething можно вызывать более одного раза для каждого рендера, это не сработает из-за асинхронных свойств setState:

const doSomething = (name, value) => {
  setValues({ ...values, [name]: value })
}

Является ли подход изменения значений непосредственно в этом случае правильным?

1 Ответ

4 голосов
/ 15 марта 2019

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

const { useState } = React;

function App() {
  const [values, setValues] = useState({});

  const doSomething = (name, value) => {
    values[name] = value;
    setValues(values);
  };

  return (
    <div onClick={() => doSomething(Math.random(), Math.random())}>
      {JSON.stringify(values)}
    </div>
  );
}

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

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

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

const doSomething = (name, value) => {
  setValues(values => ({ ...values, [name]: value }))
}

const { useState } = React;

function App() {
  const [values, setValues] = useState({});

  const doSomething = (name, value) => {
    setValues(values => ({ ...values, [name]: value }));
  };

  return (
    <div onClick={() => doSomething(Math.random(), Math.random())}>
      {JSON.stringify(values)}
    </div>
  );
}

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

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