Denne artikel blev oprindeligt publiceret på www.aboutmonica.com.
Jeg har for nylig oprettet en Stimulus Check Calculator baseret på tal fra CARES Act og Washington Post for at hjælpe folk med at vurdere mængden af deres stimuluscheck i henhold til CARES Act.
Denne artikel vil gennemgå, hvordan jeg refaktorerede regnemaskinens tilstandsstyring ved at konsolidere flere useState()
React hooks i en enkelt useReducer()
. useReducer()
er et alternativ, der kan overvejes, når du bruger useState()
at styre tilstand i funktionelle React-komponenter. Denne artikel forudsætter en vis fortrolighed med statsstyring i React and React Hooks.
Skærmbillede af Stimulus Check Calculator.
Oversigt:
- Administrer formulartilstand med useState();
- Indstilling af starttilstanden med useState()
- Opdaterer formulartilstand med useState()
- Administrer formulartilstand med useReducer();
- Indstilling af starttilstanden med useReducer()
- Opdaterer formulartilstand med useReducer()
- Fuld kildekode med eksempler
- kildekode ved hjælp af useState():
- kildekode ved hjælp af useReducer():
Håndtering af formulartilstand med useState();
For at bruge useState()
Reaktionskrog til tilstandsstyring af den lommeregner, som jeg først skulle importere useState
fra React.
import { useState } from "react";
Indstilling af starttilstanden med useState()
Derefter inden for den funktion, der returnerer Form
komponent I opsætter useState()
kroge til taxYear
, filingStatus
,income
, children
og stimulusAmount
.
const { SINGLE, HEADOFHOUSE, MARRIED } = filingStatuses;
const [taxYear, setTaxYear] = useState(2019);
const [filingStatus, setFilingStatus] = useState(SINGLE);
const [income, setIncome] = useState("75000");
const [children, setChildren] = useState(0);
const [stimulusAmount, setStimulusAmount] = useState(-1);
Parameteren blev overført til useState()
repræsenterer standardværdien for den pågældende tilstand. Det betyder, at linjen nedenfor angiver standardværdien taxYear
i tilstand til 2019
.
const [taxYear, setTaxYear] = useState(2019);
Opdaterer formulartilstand med useState()
Hændelseshandlere, såsom onChange
eller onClick
kan bruges til at opdatere komponentens tilstand, når data, når en formular ændres. Administration af formulartilstand ved at opdatere komponentens interne tilstand betragtes som en "kontrolleret komponent" i forhold til at lade DOM administrere formularens tilstand.
For at opdatere taxYear
's værdi til det valgte år, er der en onClick
hændelseshandler, der kalder setTaxYear(year)
med year
parameter er den aktuelle year
der er valgt.
{[2019, 2018].map(year => (
<button
onClick={() => setTaxYear(year)}
className={year == taxYear ? "selectedButton" : ""}
key={year}
name="tax-year"
>
{year == 2019 ? "Yes" : "No"}
</button>
))}
Lignende logik bruges til at opdatere filingStatus
income
og children
, stimulusAmount
og handleSubmit
når formulardata opdateres eller indsendes.
## Håndtering af formulartilstand med useReducer();
For at bruge useReducer()
React hook til tilstandsstyring af den lommeregner, jeg først skulle bruge for at importere useReducer
fra React. Hvis du ikke er bekendt med reducers
i JavaScript tjek min artikel om Understanding Reduce i Javascript
import { useReducer } from "react";
Indstilling af starttilstanden med useReducer()
Så indstiller jeg starttilstanden for komponenten som:
const initialState = {
taxYear: 2019,
filingStatus: SINGLE,
income: "75000",
children: 0,
stimulusAmount: -1,
};
const [state, dispatch] = useReducer(reducer, initialState);
Svarende til useState
, useReducer
returnerer den relaterede tilstand sammen med en metode til at opdatere tilstanden. Med useReducer
i stedet for at opdatere tilstanden ved at sende en værdi til setState()
en handling skal afsendes, som kalder reducer
.
I mit tilfælde reducer
funktion så sådan ud:
function reducer(state, action) {
const { type, payload } = action;
return { ...state, [type]: payload };
}
Opdaterer formulartilstand med useReducer()
Hver gang dispatch
hedder det skal kaldes med en action
element, der indeholder en type
og i dette særlige tilfælde en payload
såvel. Skatteårets tilstand kan opdateres onClick
ved at skyde
onClick={() => dispatch({ type: "taxYear", payload: year })}
i stedet for
onClick={() => setTaxYear(year)}
reducer(state, action)
forventer at modtage en action
det er et objekt med type
og payload
. Inden for reduceringsfunktionen er handlingens type
og payload
bruges til at returnere den aktuelle state
med [type]: payload
overskrevet.
const { type, payload } = action;
return { ...state, [type]: payload };
I tilfælde af opdatering af staten fra 2017, hvis den nuværende tilstand var:
const initialState = {
taxYear: 2019,
filingStatus: SINGLE,
income: "75000",
children: 0,
stimulusAmount: -1,
};
Affyr derefter onClick={() => dispatch({ type: "taxYear", payload: 2018 })}
ville resultere i, at reducereren returnerer den aktuelle tilstand, men kun med værdien taxYear
overskrevet og indstillet til 2018. Bemærk:dette fungerer som skrevet, fordi for hver handling i dette eksempel type
handling er den samme som dens tilsvarende nøgleværdi i state
.
Fuld kildekode med eksempler
Den fulde kildekode nedenfor sammenligner de fulde implementeringer af tilstandsstyringsmetoderne ovenfor. Som illustreret ovenfor, useReducer()
er en anden React hook, der kan bruges til tilstandsstyring og kan implementeres på en måde, der tillader logik fra useState()
kroge, der skal konsolideres. Den relaterede kildekode til den aktuelle version af lommeregneren er tilgængelig på GitHub.
kildekode ved hjælp af useState():
import { filingStatuses } from "../utils/constants";
import { getStimulusAmount } from "../utils/calculateStimulus";
import { useState } from "react";
function Form() {
const { SINGLE, HEADOFHOUSE, MARRIED } = filingStatuses;
const [taxYear, setTaxYear] = useState(2019);
const [filingStatus, setFilingStatus] = useState(SINGLE);
const [income, setIncome] = useState("75000");
const [children, setChildren] = useState(0);
const [stimulusAmount, setStimulusAmount] = useState(-1);
function handleSubmit(e) {
e.preventDefault();
setStimulusAmount(calculateStimulus(income, filingStatus, children));
}
return (
<form onSubmit={handleSubmit}>
<label htmlFor="tax-year">Have you filed your 2019 taxes yet?</label>
{[2019, 2018].map(year => (
<button
onClick={() => setTaxYear(year)}
className={year == taxYear ? "selectedButton" : ""}
key={year}
name="tax-year"
>
{year == 2019 ? "Yes" : "No"}
</button>
))}
<label htmlFor="filing-status">
What was your filing status in your {taxYear} taxes?{" "}
</label>
{[SINGLE, MARRIED, HEADOFHOUSE].map(status => (
<button
onClick={() => setFilingStatus(status)}
className={status == filingStatus ? "selectedButton" : ""}
name="filing-status"
key={status}
>
{" "}
{status}
</button>
))}
<br />
<label htmlFor="adjusted-income">
What was your adjusted gross income in {taxYear}?
</label>
${" "}
<input
type="number"
inputMode="numeric"
pattern="[0-9]*"
value={income}
onChange={e => setIncome(e.target.value)}
min={0}
name="adjusted-income"
/>
<br />
<label htmlFor="children">
How many children under age 17 did you claim as dependents in{" "}
{taxYear}?
</label>
<input
type="number"
inputMode="numeric"
pattern="[0-9]*"
value={children}
onChange={e => setChildren(e.target.value)}
min={0}
name="label"
/>
<br />
<button type="submit" className="calculateButton">
Calculate
</button>
<p>
{" "}
{stimulusAmount >= 0 &&
(stimulusAmount > 0
? `Your stimulus amount is expected to be $${stimulusAmount}.`
: `You are not expected to receive a stimulus.`)}
</p>
<br />
</form>
);
}
export default Form;
kildekode ved hjælp af useReducer():
import { useReducer } from "react";
import { filingStatuses } from "../utils/constants";
import { getStimulusAmount } from "../utils/calculateStimulus";
function reducer(state, action) {
const { type, payload } = action;
return { ...state, [type]: payload };
}
function Form() {
const { SINGLE, HEADOFHOUSE, MARRIED } = filingStatuses;
const initialState = {
taxYear: 2019,
filingStatus: SINGLE,
income: "75000",
children: 0,
stimulusAmount: -1,
};
const [state, dispatch] = useReducer(reducer, initialState);
function handleSubmit(e) {
e.preventDefault();
dispatch({
type: "stimulusAmount",
payload: getStimulusAmount(income, filingStatus, children),
});
}
const { taxYear, filingStatus, income, children, stimulusAmount } = state;
return (
<form onSubmit={handleSubmit}>
<label htmlFor="tax-year">Have you filed your 2019 taxes yet?</label>
{[2019, 2018].map((year) => (
<button
onClick={() => dispatch({ type: "taxYear", payload: year })}
className={year == taxYear ? "selectedButton" : ""}
key={year}
name="tax-year"
>
{year == 2019 ? "Yes" : "No"}
</button>
))}
<label htmlFor="filing-status">
What was your filing status in your {taxYear} taxes?{" "}
</label>
{[SINGLE, MARRIED, HEADOFHOUSE].map((status) => (
<button
onClick={() => dispatch({ type: "filingStatus", payload: status })}
className={status == filingStatus ? "selectedButton" : ""}
name="filing-status"
key={status}
>
{" "}
{status}
</button>
))}
<br />
<label htmlFor="adjusted-income">
What was your adjusted gross income in {taxYear}?
</label>
${" "}
<input
type="string"
inputMode="numeric"
pattern="[0-9]*"
value={income}
onChange={(e) => dispatch({ type: "income", payload: e.target.value })}
min={0}
/>
<br />
<label htmlFor="children">
How many children under age 17 did you claim as dependents in {taxYear}?
</label>
<input
type="number"
inputMode="numeric"
pattern="[0-9]*"
value={children}
onChange={(e) =>
dispatch({ type: "children", payload: e.target.value })
}
min={0}
name="label"
/>
<br />
<button type="submit" className="calculateButton">
Calculate
</button>
<p>
{" "}
{stimulusAmount >= 0 &&
(stimulusAmount > 0
? `Your stimulus amount is likely to be ${new Intl.NumberFormat(
"en-US",
{ style: "currency", currency: "USD" }
).format(stimulusAmount)}.`
: `You are not expected to receive a stimulus.`)}
</p>
<br />
</form>
);
}
export default Form;