O que é useState () no React?

133

Atualmente, estou aprendendo o conceito de ganchos no React e tentando entender o exemplo abaixo.

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>
  );
}

O exemplo acima incrementa o contador no próprio parâmetro de função do manipulador. E se eu quiser modificar o valor da contagem dentro da função do manipulador de eventos

Considere o exemplo abaixo

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>
Hemadri Dasari
fonte
Você também pode procurar no código fonte para entender como useStateé implementado. Aqui está a definição da versão 16.9 .
chemturion 13/09/19

Respostas:

148

Ganchos de reação são uma nova maneira (ainda em desenvolvimento) de acessar os principais recursos de reação, como statesem a necessidade de usar classes. No seu exemplo, se você deseja incrementar um contador diretamente na função do manipulador sem especificá-lo diretamente no onClickprop, poderia fazer algo como:

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

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

e onClick:

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

Vamos explicar rapidamente o que está acontecendo nesta linha:

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

useState(0)retorna uma tupla em que o primeiro parâmetro counté o estado atual do contador e setCounteré o método que nos permitirá atualizar o estado do contador. Podemos usar o setCountermétodo para atualizar o estado de countqualquer lugar - Nesse caso, estamos usando-o dentro da setCountfunção em que podemos fazer mais coisas; a idéia com hooks é que somos capazes de manter nosso código mais funcional e evitar componentes baseados em classe, se não for desejado / necessário.

Eu escrevi um artigo completo sobre ganchos com vários exemplos (incluindo contadores), como este codepen , fiz uso de useState, useEffect, useContext, e ganchos feitos sob encomenda . Eu poderia entrar em mais detalhes sobre como os ganchos funcionam nessa resposta, mas a documentação faz um bom trabalho explicando o gancho de estado e outros ganchos em detalhes, espero que ajude.

update: Os ganchos não são mais uma proposta , já que a versão 16.8 agora está disponível para uso, há uma seção no site do React que responde a algumas das perguntas frequentes .

Enmanuel Duran
fonte
2
Boa analogia, exceto que o JavaScript não tecnicamente tem um tipo de dados tuple
goonerify
Bem, a atribuição desestruturada é usada como tupla stackoverflow.com/a/4513061/6335029
NaveenDA
Os ganchos são assíncronos? Ao usar setSomething, se eu tentar usar somethingdiretamente depois, parece que o valor antigo ainda é ...
Byron Coetsee
51

useStateé um dos ganchos de reação integrados disponíveis na 0.16.7versão.

useStatedeve ser usado apenas dentro de componentes funcionais. useStateé o caminho se precisamos de um estado interno e não precisamos implementar lógica mais complexa, como métodos de ciclo de vida.

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

Retorna um valor com estado e uma função para atualizá-lo.

Durante a renderização inicial, o estado retornado (state) é igual ao valor passado como o primeiro argumento (initialState).

A função setState é usada para atualizar o estado. Ele aceita um novo valor de estado e enfileira uma nova renderização do componente.

Observe que o useStateretorno de chamada do gancho para atualizar o estado se comporta de maneira diferente dos componentes this.setState. Para mostrar a diferença, preparei dois exemplos.

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/[email protected]/umd/react.development.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>

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

Um novo objeto é criado quando o setUserInforetorno de chamada é usado. Observe que perdemos o lastNamevalor da chave. Para consertar que poderíamos passar a função para dentro useState.

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

Consultar exemplo:

// 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/[email protected]/umd/react.development.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>

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

Diferente do método setState encontrado nos componentes da classe, useState não mescla automaticamente os objetos de atualização. Você pode replicar esse comportamento combinando o formulário do atualizador de funções com a sintaxe de propagação do objeto:

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

Para mais informações, useStateconsulte a documentação oficial .

Loelsonk
fonte
2
Obrigado por adicionar uma função como parâmetro no exemplo.
Juni Brosas
15

A sintaxe do useStategancho é direta.

const [value, setValue] = useState(defaultValue)

Se você não estiver familiarizado com esta sintaxe, acesse aqui .

Eu recomendo que você leia a documentação . Existem excelentes explicações com uma quantidade razoável de exemplos.

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>
   );
 }

Jan Ciołek
fonte
Essa deve ser a resposta aceita. Conciso e claro, com boas referências externas.
varun 07/07
8

useStateé um dos ganchos disponíveis no React v16.8.0. Basicamente, você pode transformar seus componentes funcionais ou não-stateful em um que possa ter seu próprio estado.

No nível muito básico, é usado desta maneira:

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

Isso permite chamar a setLoadingpassagem de um valor booleano. É uma maneira legal de ter um componente funcional "com estado".

codejockie
fonte
7

useState()é um gancho de reação. Ganchos possibilitam o uso de estado e mutabilidade dentro dos componentes da função.

Enquanto você não pode usar ganchos dentro de classes, pode envolver seu componente de classe com uma função um e usar ganchos a partir dele. Essa é uma ótima ferramenta para migrar componentes da classe para o formulário da função. Aqui está um exemplo completo:

Neste exemplo, usarei um componente de contador. É isso:

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>

É um componente de classe simples com um estado de contagem e a atualização do estado é feita por métodos. Esse é um padrão muito comum nos componentes de classe. A primeira coisa é envolvê-lo com um componente de função com o mesmo nome, que delega todas as suas propriedades ao componente encapsulado. Também é necessário renderizar o componente agrupado no retorno da função. Aqui está:

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>

Este é exatamente o mesmo componente, com o mesmo comportamento, o mesmo nome e as mesmas propriedades. Agora vamos elevar o estado de contagem para o componente de função. É assim que vai:

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>

Note que o método incainda está lá, não fará mal a ninguém, na verdade é um código morto. Essa é a ideia, continue aumentando o estado. Depois de terminar, você pode remover o componente de classe:

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>

Embora isso possibilite o uso de ganchos dentro dos componentes da classe, não recomendo que você faça isso, exceto se estiver migrando como eu fiz neste exemplo. A mistura de componentes de função e classe fará com que o gerenciamento de estado seja uma bagunça. Eu espero que isso ajude

Cumprimentos

lagartixas
fonte
7

useState () é um exemplo do gancho React interno que permite usar estados em seus componentes funcionais. Isso não foi possível antes do React 16.7.

A função useState é um gancho interno que pode ser importado do pacote react. Permite adicionar estado aos seus componentes funcionais. Usando o gancho useState dentro de um componente de função, você pode criar um pedaço de estado sem alternar para componentes de classe.

Muhammad Shaheem
fonte
5

Ganchos são um novo recurso no React v16.7.0-alpha useState"Gancho". useState()defina o valor padrão de qualquer variável e gerencie no componente de função (funções PureComponent). ex : const [count, setCount] = useState(0);defina o valor padrão da contagem 0. e você pode usar setCountpara incrementou decremento valor. onClick={() => setCount(count + 1)}incrementar o valor da contagem. DOC

Asif vora
fonte
4

Obrigado loelsonk, eu fiz isso

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})}/>
    )

Янов Алексей
fonte
2

useState é um gancho que permite adicionar estado a um componente funcional. Ele aceita um argumento que é o valor inicial da propriedade state e retorna o valor atual da propriedade state e um método capaz de atualizar essa propriedade state.
A seguir, é apresentado um exemplo simples:
import React, {useState} from react
function HookCounter {
const [count, stateCount]= useState(0)
return(
<div>
<button onClick{( ) => setCount(count+1)}> count{count} </button>
</div>
)
}

useState aceita o valor inicial da variável de estado que é zero nesse caso e retorna um par de valores. O valor atual do estado foi chamado de contagem e um método que pode atualizar a variável de estado foi chamado de setCount.

Abhishek Kumar
fonte