javascript - er det mulig å bruke React.useState(() => {}) i React?


er det mulig å bruke en function som tilstanden til min React-komponent?

eksempel kode her:

// typescript 
type OoopsFunction = () => void;

export function App() {
    const [ooops, setOoops] = React.useState<OoopsFunction>(
        () => console.log('default ooops')
    );

    return (
        <div>
            <div onClick={ ooops }>
                Show Ooops
            </div>

            <div onClick={() => {
                setOoops(() => console.log('other ooops'))
            }}>
                change oops
            </div>
        </div>
    )
}

men det fungerer ikke ... defaultOoops vil bli kalt helt i starten, og når man klikker på change oops, vil otrher ooops bli logget til konsollen umiddelbart, ikke etter å ha klikket på Show Ooops igjen.

hvorfor ?

er det mulig for meg å bruke en funksjon som min komponents tilstand?

ellers har React sine spesielle måter å behandle slik funksjonstilstand?

Svar #1

Det er mulig å sette en funksjon i state ved bruk av hooks, men fordi state kan initialiseres og oppdateres med en funksjon som returnerer den initiale staten eller den oppdaterte staten, må du levere en funksjon som igjen returnerer funksjonen du vil legge i state.

const { useState } = React;

function App() {
  const [ooops, setOoops] = useState(() => () => console.log("default ooops"));

  return (
    <div>
      <button onClick={ooops}>Show Ooops</button>

      <button
        onClick={() => {
          setOoops(() => () => console.log("other ooops"));
        }}
      >
        change oops
      </button>
    </div>
  );
}

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root"></div>

Svar #2

Kort fortalt

Ja, det er mulig å bruke en funksjon som React-komponentens tilstand. For å gjøre dette må du bruke en funksjon som returnerer din funksjon i React.useState:

const [ooops, setOoops] = React.useState<OoopsFunction>(
    () => () => console.log('default ooops')
);

// or

const yourFunction = () => console.log('default ooops');
const [ooops, setOoops] = React.useState<OoopsFunction>(
    () => yourFunction
);

For å oppdatere funksjonen din må du også bruke en funksjon som returnerer funksjonen din:

setOoops(() => () => console.log("other ooops"));

// or

const otherFunction = () => console.log("other ooops");
setOoops(() => otherFunction);

Detaljert svar

Notater om React.useState

Signaturen til useState i React med typer er

function useState<S>(initialState: S | (() => S)): [S, Dispatch<SetStateAction<S>>];

Det viser at det finnes to måter å sette startverdien i tilstanden din på:

  1. Gi startverdien som den er (React.useState(0) - startverdi 0),
  2. Gi en funksjon som returnerer startverdien som skal settes (React.useState(() => 0) - startverdien er også 0).

Viktig å merke: Hvis du gir en funksjon i React.useState, så blir denne funksjonen utført når React.useState kjøres, og den returnerte verdien lagres som den opprinnelige tilstanden.

Hvordan faktisk lagre funksjoner

Problemet her er at hvis du vil lagre en funksjon som tilstand, kan du ikke gi den som initialtilstand som den er, fordi dette resulterer i at funksjonen blir utført og returverdien blir lagret som tilstand i stedet for selve funksjonen. Derfor når du skriver

const [ooops, setOoops] = React.useState<OoopsFunction>(
    () => console.log('default ooops')
);

`'default ooops'` logges umiddelbart når `React.useState` blir kalt, og returverdien (i dette tilfellet `undefined`) blir lagret.

Dette kan unngås ved å gi en høyere ordens funksjon som returnerer funksjonen du ønsker å lagre:

const [ooops, setOoops] = React.useState<OoopsFunction>(
    () => () => console.log('default ooops')
);

På denne måten vil den ytre funksjonen definitivt bli utført når React.useState kjøres for første gang, og returverdien vil bli lagret. Siden denne returverdien nå er din nødvendige funksjon, vil denne funksjonen bli lagret.

Notater om tilstandsinnstillingsfunksjonen

Signaturen til statsetterfunksjonen (her setOoops) er gitt som

Dispatch<SetStateAction<S>>

med

type Dispatch<A> = (value: A) => void;
type SetStateAction<S> = S | ((prevState: S) => S);

Som i React.useState finnes det også mulighet til å oppdatere tilstanden med en verdi eller en funksjon som returnerer verdien. Så for å oppdatere tilstanden må den høyere ordens funksjonen fra oven også brukes.

Relaterte artikler