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.