Czym jest useState () w Reakcie?

134

Obecnie uczę się koncepcji hooków w Reakcie i próbuję zrozumieć poniższy przykład.

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

Powyższy przykład zwiększa licznik w samym parametrze funkcji obsługi. Co zrobić, jeśli chcę zmodyfikować wartość licznika w funkcji obsługi zdarzeń

Rozważ poniższy przykład

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
źródło
Możesz również zajrzeć do kodu źródłowego, aby zrozumieć, jak useStatejest zaimplementowany. Oto definicja od wersji 16.9 .
chemturion

Odpowiedzi:

150

Uchwyty React to nowy sposób (wciąż rozwijany) uzyskiwania dostępu do podstawowych funkcji reakcji, takich jak statebez konieczności używania klas, w twoim przykładzie, jeśli chcesz zwiększyć licznik bezpośrednio w funkcji obsługi bez określania go bezpośrednio w właściwości onClick, mógłby zrobić coś takiego:

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

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

i onClick:

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

Szybko wyjaśnijmy, co się dzieje w tej linii:

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

useState(0)zwraca krotkę, w której pierwszy parametr countjest bieżącym stanem licznika i setCounterjest metodą, która pozwoli nam zaktualizować stan licznika. Możemy użyć setCountermetody, aby zaktualizować stan countdowolnego miejsca - w tym przypadku używamy jej wewnątrz setCountfunkcji, w której możemy zrobić więcej rzeczy; idea haków jest taka, że ​​jesteśmy w stanie utrzymać nasz kod bardziej funkcjonalny i unikać komponentów opartych na klasach, jeśli nie są one pożądane / potrzebne.

Napisałem cały artykuł o hakach z wielu przykładów (w tym liczników), takich jak ten codepen , zrobiłem wykorzystanie useState, useEffect, useContext, i niestandardowych haków . Mógłbym uzyskać więcej szczegółów na temat tego, jak działają hooki w tej odpowiedzi, ale dokumentacja bardzo dobrze objaśnia podpięcie stanu i inne szczegóły, mam nadzieję, że to pomoże.

aktualizacja: Haki nie są już propozycją , ponieważ wersja 16.8 jest już dostępna do użycia, w witrynie Reacta jest sekcja, która zawiera odpowiedzi na niektóre z często zadawanych pytań .

Enmanuel Duran
źródło
2
Dobra analogia, z tym wyjątkiem, że JavaScript z technicznego punktu widzenia nie ma typu danych krotki
goonerify
Cóż, zniszczone przypisanie jest używane jak tuple stackoverflow.com/a/4513061/6335029
NaveenDA
Czy haki są asynchroniczne? Podczas używania setSomething, jeśli spróbuję użyć somethingbezpośrednio później, wydaje się, że nadal ma starą wartość ...
Byron Coetsee
51

useStatejest jednym z wbudowanych zaczepów reagujących dostępnych w 0.16.7wersji.

useStatenależy stosować tylko wewnątrz elementów funkcjonalnych. useStatejest sposobem, jeśli potrzebujemy stanu wewnętrznego i nie musimy implementować bardziej złożonej logiki, takiej jak metody cyklu życia.

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

Zwraca wartość stanową i funkcję do jej aktualizacji.

Podczas początkowego renderowania zwracany stan (stan) jest taki sam, jak wartość przekazana jako pierwszy argument (initialState).

Funkcja setState służy do aktualizacji stanu. Akceptuje nową wartość stanu i umieszcza w kolejce ponowne renderowanie komponentu.

Należy pamiętać, że useStatewywołanie zwrotne hook w celu aktualizacji stanu zachowuje się inaczej niż komponenty this.setState. Aby pokazać różnicę, przygotowałem dwa przykłady.

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>

Nowy obiekt jest tworzony, gdy setUserInfoużywane jest wywołanie zwrotne. Zauważ, że straciliśmy lastNamekluczową wartość. Aby to naprawić, mogliśmy przekazać funkcję wewnątrz useState.

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

Zobacz przykład:

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

W przeciwieństwie do metody setState znajdującej się w komponentach klas, useState nie łączy automatycznie obiektów aktualizacji. Możesz powtórzyć to zachowanie, łącząc formularz aktualizacji funkcji ze składnią rozprzestrzeniania obiektów:

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

Więcej informacji można useStateznaleźć w oficjalnej dokumentacji .

loelsonk
źródło
2
Dziękujemy za dodanie funkcji jako parametru w przykładzie.
Juni Brosas
15

Składnia useStatehooka jest prosta.

const [value, setValue] = useState(defaultValue)

Jeśli nie znasz tej składni, przejdź tutaj .

Polecam przeczytanie dokumentacji . Istnieją doskonałe wyjaśnienia z przyzwoitą liczbą przykładów.

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
źródło
To powinna być akceptowana odpowiedź. Zwięzłe i jasne, z dobrymi odniesieniami zewnętrznymi.
varun
8

useStatejest jednym z haków dostępnych w React 16.8.0. W zasadzie pozwala ci zmienić twoje bezstanowe / funkcjonalne komponenty na takie, które mogą mieć swój własny stan.

Na bardzo podstawowym poziomie jest używane w ten sposób:

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

To z kolei pozwala wywołać setLoadingprzekazanie wartości logicznej. To fajny sposób na posiadanie „stanowego” elementu funkcjonalnego.

codejockie
źródło
7

useState()jest hakiem React. Haki umożliwiają użycie stanu i zmienności wewnątrz komponentów funkcji.

Chociaż nie możesz używać punktów zaczepienia wewnątrz klas, możesz opakować komponent klasy funkcją numer jeden i użyć z niego punktów zaczepienia. To świetne narzędzie do migracji komponentów z klasy do formy funkcji. Oto pełny przykład:

W tym przykładzie użyję komponentu licznika. To jest to:

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>

Jest to prosty składnik klasy ze stanem zliczania, a aktualizacja stanu odbywa się za pomocą metod. Jest to bardzo powszechny wzorzec w komponentach klas. Pierwszą rzeczą jest owinięcie go komponentem funkcji o tej samej nazwie, który deleguje wszystkie swoje właściwości do opakowanego komponentu. Musisz także wyrenderować opakowany komponent w funkcji return. Oto ona:

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>

To jest dokładnie ten sam komponent, z takim samym zachowaniem, tą samą nazwą i tymi samymi właściwościami. Teraz podnieśmy stan liczenia do składnika funkcji. Oto jak to działa:

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>

Zauważ, że metoda incnadal istnieje, nikomu nie zaszkodzi, w rzeczywistości jest martwym kodem. To jest idea, po prostu podnoś stan. Po zakończeniu możesz usunąć komponent klasy:

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>

Chociaż umożliwia to użycie haków wewnątrz komponentów klas, nie polecałbym tego robić, chyba że migracja jest taka, jak w tym przykładzie. Mieszanie składników funkcji i klas spowoduje bałagan w zarządzaniu stanem. mam nadzieję, że to pomoże

Z poważaniem

gekony
źródło
7

useState () to przykład wbudowanego hooka w React, który pozwala używać stanów w komponentach funkcjonalnych. Nie było to możliwe przed React 16.7.

Funkcja useState to wbudowany punkt zaczepienia, który można zaimportować z pakietu reagowania. Pozwala na dodanie stanu do komponentów funkcjonalnych. Używając hooka useState wewnątrz komponentu funkcji, możesz stworzyć stan bez przełączania się na komponenty klas.

Muhammad Shaheem
źródło
5

Haczyki to nowa funkcja w programie React v16.7.0-alpha useStateto „Hak”. useState()ustaw wartość domyślną dowolnej zmiennej i zarządzaj w komponencie funkcji (funkcje PureComponent). ex : const [count, setCount] = useState(0);ustawić domyślną wartość count 0. iu można użyć setCountto incrementlub decrementwartość. onClick={() => setCount(count + 1)}zwiększyć wartość licznika. DOC

Asif vora
źródło
5

Dzięki Loelsonk, zrobiłem to

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

Janow
źródło
2

useState to punkt zaczepienia, który umożliwia dodanie stanu do składnika funkcjonalnego. Przyjmuje argument, który jest początkową wartością właściwości stanu i zwraca bieżącą wartość właściwości stanu oraz metodę, która jest w stanie zaktualizować tę właściwość stanu.
Oto prosty przykład:
import React, {useState} from react
function HookCounter {
const [count, stateCount]= useState(0)
return(
<div>
<button onClick{( ) => setCount(count+1)}> count{count} </button>
</div>
)
}

useState akceptuje początkową wartość zmiennej stanu, która w tym przypadku wynosi zero i zwraca parę wartości. Bieżąca wartość stanu została nazwana count, a metoda, która może aktualizować zmienną stanu została wywołana jako setCount.

Abhishek Kumar
źródło