Что такое useState () в React?

134

В настоящее время я изучаю концепцию хуков в React и пытаюсь понять приведенный ниже пример.

import { useState } from 'react';

function Example() {
    // Declare a new state variable, which we'll call "count"
    const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

В приведенном выше примере увеличивается счетчик самого параметра функции-обработчика. Что, если я хочу изменить значение счетчика внутри функции обработчика событий

Рассмотрим ниже пример

setCount = () => {
  //how can I modify count value here. Not sure if I can use setState to modify its value
  //also I want to modify other state values as well here. How can I do that
}

<button onClick={() => setCount()}>
  Click me
</button>
Хемадри Дасари
источник
Вы также можете посмотреть исходный код, чтобы понять, как useStateэто реализовано. Вот определение версии 16.9 .
chemturion

Ответы:

151

Перехватчики React - это новый способ (все еще разрабатываемый) для доступа к основным функциям реакции, например, stateбез использования классов, в вашем примере, если вы хотите увеличить счетчик непосредственно в функции обработчика, не указывая его непосредственно в onClickопоре, вы может сделать что-то вроде:

...
const [count, setCounter] = useState(0);
const [moreStuff, setMoreStuff] = useState(...);
...

const setCount = () => {
    setCounter(count + 1);
    setMoreStuff(...);
    ...
};

и onClick:

<button onClick={setCount}>
    Click me
</button>

Давайте быстро объясним, что происходит в этой строке:

const [count, setCounter] = useState(0);

useState(0)возвращает кортеж, где первый параметр count- это текущее состояние счетчика и setCounterметод, который позволит нам обновить состояние счетчика. Мы можем использовать этот setCounterметод для обновления состояния countгде угодно - в этом случае мы используем его внутри setCountфункции, где мы можем делать больше вещей; идея с крючками состоит в том, что мы можем сохранить наш код более функциональным и избегать компонентов на основе классов, если они не желательны / не нужны.

Я написал статью полностью о крючках с несколькими примерами (включая счетчики) , такие как это codepen , я использовал useState, useEffect, useContextи пользовательские крючки . Я мог бы подробнее рассказать о том, как работают хуки в этом ответе, но документация очень хорошо объясняет ловушку состояния и другие хуки, надеюсь, это поможет.

update: хуки больше не являются предложением , так как теперь они доступны для использования в версии 16.8, на сайте React есть раздел, который отвечает на некоторые часто задаваемые вопросы .

Энмануэль Дюран
источник
2
Хорошая аналогия, за исключением того, что в JavaScript технически нет типа данных кортеж
goonerify
Ну, деструктурированное присваивание используется как кортеж stackoverflow.com/a/4513061/6335029
NaveenDA
Асинхронные хуки? При использовании setSomething, если я затем попробую использовать somethingсразу после этого, кажется, что у него все еще старое значение ...
Байрон Кутси,
51

useStateэто один из встроенных хуков реагирования, доступных в 0.16.7версии.

useStateследует использовать только внутри функциональных компонентов. useStateэто способ, если нам нужно внутреннее состояние и не нужно реализовывать более сложную логику, такую ​​как методы жизненного цикла.

const [state, setState] = useState(initialState);

Возвращает значение с состоянием и функцию для его обновления.

Во время первоначального рендеринга возвращаемое состояние (состояние) совпадает со значением, переданным в качестве первого аргумента (initialState).

Функция setState используется для обновления состояния. Он принимает новое значение состояния и ставит в очередь повторную визуализацию компонента.

Обратите внимание, что useStateобратный вызов ловушки для обновления состояния ведет себя иначе, чем компоненты this.setState. Чтобы показать вам разницу, я приготовил два примера.

class UserInfoClass extends React.Component {
  state = { firstName: 'John', lastName: 'Doe' };
  
  render() {
    return <div>
      <p>userInfo: {JSON.stringify(this.state)}</p>
      <button onClick={() => this.setState({ 
        firstName: 'Jason'
      })}>Update name to Jason</button>
    </div>;
  }
}

// Please note that new object is created when setUserInfo callback is used
function UserInfoFunction() {
  const [userInfo, setUserInfo] = React.useState({ 
    firstName: 'John', lastName: 'Doe',
  });

  return (
    <div>
      <p>userInfo: {JSON.stringify(userInfo)}</p>
      <button onClick={() => setUserInfo({ firstName: 'Jason' })}>Update name to Jason</button>
    </div>
  );
}

ReactDOM.render(
  <div>
    <UserInfoClass />
    <UserInfoFunction />
  </div>
, document.querySelector('#app'));
<script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>

<div id="app"></div>

Новый объект создается при использовании setUserInfoобратного вызова. Обратите внимание, мы потеряли lastNameключевое значение. Чтобы исправить это, мы могли передавать функцию внутрь useState.

setUserInfo(prevState => ({ ...prevState, firstName: 'Jason' })

См. Пример:

// Please note that new object is created when setUserInfo callback is used
function UserInfoFunction() {
  const [userInfo, setUserInfo] = React.useState({ 
    firstName: 'John', lastName: 'Doe',
  });

  return (
    <div>
      <p>userInfo: {JSON.stringify(userInfo)}</p>
      <button onClick={() => setUserInfo(prevState => ({
        ...prevState, firstName: 'Jason' }))}>
        Update name to Jason
      </button>
    </div>
  );
}

ReactDOM.render(
    <UserInfoFunction />
, document.querySelector('#app'));
<script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>

<div id="app"></div>

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

setState(prevState => {
  // Object.assign would also work
  return {...prevState, ...updatedValues};
});

Подробнее useStateсм. В официальной документации .

loelsonk
источник
2
Спасибо за добавление функции в качестве параметра в пример.
Джуни Бросас,
15

Синтаксис useStateловушки прост.

const [value, setValue] = useState(defaultValue)

Если вы не знакомы с этим синтаксисом, перейдите сюда .

Я бы порекомендовал вам прочитать документацию. Там есть отличные объяснения с приличным количеством примеров.

import { useState } from 'react';

function Example() {
    // Declare a new state variable, which we'll call "count"
    const [count, setCount] = useState(0);
  
  // its up to you how you do it
  const buttonClickHandler = e => {
   // increment
   // setCount(count + 1)
   
   // decrement
   // setCount(count -1)
   
   // anything
   // setCount(0)
  }
  

  return (
       <div>
          <p>You clicked {count} times</p>
         <button onClick={buttonClickHandler}>
             Click me
         </button>
      </div>
   );
 }

Ян Чолек
источник
Это должен быть принятый ответ. Кратко и ясно, с хорошими внешними ссылками.
Варун
8

useState- один из хуков, доступных в React v16.8.0. Это в основном позволяет вам превратить ваши компоненты, не имеющие состояния / функциональные, в компоненты, которые могут иметь собственное состояние.

На самом базовом уровне это используется следующим образом:

const [isLoading, setLoading] = useState(true);

Затем это позволяет вам вызывать setLoadingпередачу логического значения. Это отличный способ иметь функциональный компонент с отслеживанием состояния.

codejockie
источник
7

useState()это перехватчик React. Хуки позволяют использовать состояние и изменчивость внутри функциональных компонентов.

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

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

class Hello extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: props.count };
  }
  
  inc() {
    this.setState(prev => ({count: prev.count+1}));
  }
  
  render() {
    return <button onClick={() => this.inc()}>{this.state.count}</button>
  }
}

ReactDOM.render(<Hello count={0}/>, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id='root'></div>

Это простой компонент класса с состоянием подсчета, а обновление состояния выполняется методами. Это очень распространенный шаблон в компонентах класса. Во-первых, оберните его функциональным компонентом с тем же именем, который делегирует все свои свойства обернутому компоненту. Также вам необходимо отобразить завернутый компонент в возвращении функции. Вот:

function Hello(props) {
  class Hello extends React.Component {
    constructor(props) {
      super(props);
      this.state = { count: props.count };
    }

    inc() {
      this.setState(prev => ({count: prev.count+1}));
    }

    render() {
      return <button onClick={() => this.inc()}>{this.state.count}</button>
    }
  }
  return <Hello {...props}/>
}

ReactDOM.render(<Hello count={0}/>, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id='root'></div>

Это точно такой же компонент, с таким же поведением, тем же именем и одинаковыми свойствами. Теперь давайте перейдем к состоянию подсчета к функциональному компоненту. Вот как это происходит:

function Hello(props) {
  const [count, setCount] = React.useState(0);
  class Hello extends React.Component {
    constructor(props) {
      super(props);
      this.state = { count: props.count };
    }

    inc() {
      this.setState(prev => ({count: prev.count+1}));
    }

    render() {
      return <button onClick={() => setCount(count+1)}>{count}</button>
    }
  }
  return <Hello {...props}/>
}

ReactDOM.render(<Hello count={0}/>, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.6/umd/react.production.min.js" integrity="sha256-3vo65ZXn5pfsCfGM5H55X+SmwJHBlyNHPwRmWAPgJnM=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom.production.min.js" integrity="sha256-qVsF1ftL3vUq8RFOLwPnKimXOLo72xguDliIxeffHRc=" crossorigin="anonymous"></script>
<div id='root'></div>

Обратите внимание, что метод incвсе еще существует, он никому не повредит, на самом деле это мертвый код. Это идея, просто продолжайте поднимать состояние. По завершении вы можете удалить компонент класса:

function Hello(props) {
  const [count, setCount] = React.useState(0);

  return <button onClick={() => setCount(count+1)}>{count}</button>;
}

ReactDOM.render(<Hello count={0}/>, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.6/umd/react.production.min.js" integrity="sha256-3vo65ZXn5pfsCfGM5H55X+SmwJHBlyNHPwRmWAPgJnM=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom.production.min.js" integrity="sha256-qVsF1ftL3vUq8RFOLwPnKimXOLo72xguDliIxeffHRc=" crossorigin="anonymous"></script>

<div id='root'></div>

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

Наилучшие пожелания

гекконы
источник
7

useState () - это пример встроенной ловушки React, которая позволяет вам использовать состояния в ваших функциональных компонентах. Это было невозможно до React 16.7.

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

Мухаммад Шахим
источник
5

Крючки - это новая функция в React v16.7.0-alpha useState«Крючке». useState()установить значение по умолчанию для любой переменной и управлять в функциональном компоненте (функции PureComponent). ex : const [count, setCount] = useState(0);установить значение по умолчанию для count 0. и u может использовать setCountto incrementили decrementзначение. onClick={() => setCount(count + 1)}увеличить значение счетчика. DOC

Асиф вора
источник
5

Спасибо loelsonk, я так и сделал

const [dataAction, setDataAction] = useState({name: '', description: ''});

    const _handleChangeName = (data) => {
        if(data.name)
            setDataAction( prevState  => ({ ...prevState,   name : data.name }));
        if(data.description)
            setDataAction( prevState  => ({ ...prevState,   description : data.description }));
    };
    
    ....return (
    
          <input onChange={(event) => _handleChangeName({name: event.target.value})}/>
          <input onChange={(event) => _handleChangeName({description: event.target.value})}/>
    )

Янов
источник
2

useState - это ловушка, позволяющая добавлять состояние к функциональному компоненту. Он принимает аргумент, который является начальным значением свойства состояния, и возвращает текущее значение свойства состояния и метод, который может обновлять это свойство состояния.
Вот простой пример:
import React, {useState} from react
function HookCounter {
const [count, stateCount]= useState(0)
return(
<div>
<button onClick{( ) => setCount(count+1)}> count{count} </button>
</div>
)
}

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

Абхишек Кумар
источник