React Hooks - использование useState против просто переменных


12

React Hooks дают нам опцию useState, и я всегда вижу сравнения Hooks и Class-State. Но как насчет хуков и некоторых обычных переменных?

Например,

function Foo() {
    let a = 0;
    a = 1;
    return <div>{a}</div>;
}

Я не использовал крючки, и это даст мне те же результаты, что и:

function Foo() {
    const [a, setA] = useState(0);
    if (a != 1) setA(1); // to avoid infinite-loop
    return <div>{a}</div>;
}

Так в чем же разница? Использование крючков в этом случае еще сложнее ... Так зачем начинать его использовать?


Вы сравниваете две разные вещи, хотя. Вторая функция с крючками имеет возможность обновлять данные. Первый на самом деле ничего не делает. Вы могли бы просто инициализировать его, let a = 1; return <div>{a}</div>и вы получите тот же результат.
Яти

Ответы:


13

Причина в том, что если вы useStateпередаете представление. Переменные сами по себе изменяют только биты в памяти, и состояние вашего приложения может быть не синхронизировано с представлением.

Сравните эти примеры:

function Foo() {
    const [a, setA] = useState(0);
    return <div onClick={() => setA(a + 1)}>{a}</div>;
}

function Foo() {
    let a = 0;
    return <div onClick={() => a + 1}>{a}</div>;
}

В обоих случаях aизменения происходят при нажатии, но только при useStateправильном использовании представления показывает aтекущее значение.


Спасибо! Так что, если мне не нужно визуализировать представление - только способ организовать мои данные (реквизиты) в некоторый массив - я могу использовать 'let'? Это работает для меня, я просто хочу знать, что все в порядке и приемлемо.
Моше Нагар

@MosheNagar, если вы извлекаете данные из реквизита, рекомендуется использовать локальные переменные вместо того, чтобы сохранять данные в состоянии, потому что компонент все равно будет повторно отображаться при смене реквизита, поэтому представление будет синхронизировано с данными. Перевод их в состояние приведет только к ненужному повторному отображению - сначала при изменении реквизита, а затем при изменении состояния.
marzelin

Еще один способ взглянуть на этот ответ - подумать, что во втором случае переменная aбудет собирать мусор после завершения ее выполнения, а в первом - поскольку она использует useStateее, она сохранит значениеa
João Marcos Gris

Он все еще мог бы использовать, useRefесли он не хотел повторно визуализировать представление. Остается вопрос, стоит ли ему использовать локальные переменные или ссылки React. Например, если у вас есть тайм-аут, который необходимо очистить, или постоянный http-запрос с использованием axios, сохраняете ли вы тайм-аут или источник axios в переменной или в ссылке React?
Том

3
@Tom Общее правило - использовать локальные переменные для производного состояния. Для чего-либо еще используйте useRef(если вы не хотите перерисовывать) или useState(если вы хотите перерисовать). В случае таймеров, поскольку они являются побочными эффектами, они должны быть запущены в useEffectловушку. Если вы хотите timerIdтолько для целей очистки, вы можете оставить его в локальной переменной обработчика . Если вы хотите иметь возможность очистить таймер из другого места в компоненте, вы должны использовать useRef. Хранение timerIdв локальной переменной компонента было бы ошибкой, поскольку локальные переменные «сбрасываются» при каждом рендеринге.
Marzelin

1

Обновление состояния заставит компонент повторно выполнить рендеринг снова, но локальные значения - нет.

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

Так что будет лучше использовать, useStateчем обычное локальное значение.

function Foo() {
    let a = 0;
    a = 1; // there will be no re-render.
    return <div>{a}</div>;
}

function Foo() {
    const [a, setA] = useState(0);
    if (a != 1) setA(1); // re-render required
    return <div>{a}</div>;
}

0

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


0
function Foo() {
    const [a, setA] = useState(0);
    if (a != 1) setA(1); // to avoid infinite-loop
    return <div>{a}</div>;
}

эквивалентно

class Foo extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            a: 0
        };
    }
    // ...
}

Что useStateвозвращает две вещи:

  1. новая переменная состояния
  2. установщик для этой переменной

если вы позвоните, setA(1)вы бы позвонили this.setState({ a: 1 })и запустили повторную визуализацию.


0

Локальные переменные будут сбрасываться при каждом рендеринге после мутации, тогда как состояние будет обновляться:

function App() {
  let a = 0; // reset to 0 on render/re-render
  const [b, setB] = useState(0);

  return (
    <div className="App">
      <div>
        {a}
        <button onClick={() => a++}>local variable a++</button>
      </div>
      <div>
        {b}
        <button onClick={() => setB(prevB => prevB + 1)}>
          state variable b++
        </button>
      </div>
    </div>
  );
}

Редактировать serene-galileo-ml3f0

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.