Krokar är återanvändbara funktioner. De låter dig använda tillstånd och andra funktioner (t.ex. livscykelmetoder och så vidare) utan att skriva en klass. Krokfunktioner låter oss "haka in" i Reaktionstillstånds livscykel använder funktionella komponenter, vilket gör att vi kan manipulera tillståndet för våra funktionella komponenter utan att behöva konvertera dem till klasskomponenter.
Reagera införda krokar tillbaka i version 16.8 och har lagt till fler sedan dess. Vissa är mer använda och populära än andra, typ useEffect
, useState
och useContext
krokar. Jag tvivlar inte på att du har nått dem om du arbetar med React.
Men det jag är intresserad av är de mindre kända React-hakarna. Även om alla React-krokar är intressanta på sitt eget sätt, finns det fem av dem som jag verkligen vill visa dig eftersom de kanske inte dyker upp i ditt dagliga arbete – eller så kanske de gör det och att känna till dem ger dig några extra superkrafter.
Innehållsförteckning
useReducer
Smakämnen useReducer
hook är ett tillståndshanteringsverktyg som andra krokar. Specifikt är det ett alternativ till useState
krok.
Om du använder useReducer
krok för att ändra två eller flera tillstånd (eller åtgärder), behöver du inte manipulera dessa tillstånd individuellt. Kroken håller reda på alla stater och hanterar dem kollektivt. Med andra ord: den hanterar och återger tillståndsförändringar. till skillnad från useState
krok, useReducer
är lättare när det gäller att hantera många stater i komplexa projekt.
Användningsfall
useReducer
kan hjälpa till att minska komplexiteten i att arbeta med flera tillstånd. Använd det när du märker att du behöver spåra flera tillstånd kollektivt, eftersom det låter dig behandla tillståndshantering och renderingslogiken för en komponent som separata problem.
syntax
useReducer
accepterar tre argument, varav ett är valfritt:
- en reducerfunktion
initialState
- an
init
funktion (valfritt)
const [state, dispatch] = useReducer(reducer, initialState)
const [state, dispatch] = useReducer(reducer, initialState initFunction) // in the case where you initialize with the optional 3rd argument
Exempelvis
Följande exempel är ett gränssnitt som innehåller en textinmatning, räknare och knapp. Att interagera med varje element uppdaterar tillståndet. Lägg märke till hur useReducer
tillåter oss att definiera flera fall samtidigt istället för att ställa in dem individuellt.
import { useReducer } from 'react';
const reducer = (state, action) => {
switch (action.type) {
case 'INCREMENT':
return { ...state, count: state.count + 1 };
case 'DECREMENT':
return { ...state, count: state.count - 1 };
case 'USER_INPUT':
return { ...state, userInput: action.payload };
case 'TOGGLE_COLOR':
return { ...state, color: !state.color };
default:
throw new Error();
}
}
function App() {
const [state, dispatch] = useReducer(reducer, { count: 0, userInput: '', color: false })
return (
<main className="App, App-header" style={{ color: state.color ? '#000' : '#FF07FF'}}>
<input style={{margin: '2rem'}}
type="text"
value={state.userInput}
onChange={(e) => dispatch({ type: 'USER_INPUT', payload: e.target.value })}
/>
<br /><br />
<p style={{margin: '2rem'}} >{state.count}</p>
<section style={{margin: '2rem'}}>
<button onClick={(() => dispatch({ type: 'DECREMENT' }))}>-</button>
<button onClick={(() => dispatch({ type: 'INCREMENT' }))}>+</button>
<button onClick={(() => dispatch({ type: 'TOGGLE_COLOR' }))}>Color</button>
</section>
<br /><br />
<p style={{margin: '2rem'}}>{state.userInput}</p>
</main>
);
}
export default App;
Från koden ovan märkte vi hur vi enkelt kan hantera flera stater i Reducer (switch-case), visar detta fördelen med useReducer
. Detta är kraften det ger när man arbetar i komplexa applikationer med flera tillstånd.
useRef
Smakämnen useRef
hook används för att skapa refs på element för att komma åt DOM. Men mer än så returnerar den ett objekt med en .current
egenskap som kan användas under en komponents hela livscykel, vilket gör att data kan finnas kvar utan att orsaka omrendering. Så, den useRef
värdet förblir detsamma mellan renderingarna; uppdatering av referensen utlöser inte en omrendering.
Användningsfall
Nå för useRef
haka på när du vill:
- Manipulera DOM med lagrad föränderlig information.
- Få åtkomst till information från underordnade komponenter (kapslade element).
- Sätt fokus på ett element.
Det är mest användbart när du lagrar muterbar data i din app utan att orsaka omrendering.
syntax
useRef
accepterar bara ett argument, vilket är ursprungligt värde.
const newRefComponent = useRef(initialValue);
Exempelvis
Här använde jag useRef
och useState
krok för att visa hur många gånger ett program återger ett uppdaterat tillstånd när du skriver in en textinmatning.
import './App.css'
function App() {
const [anyInput, setAnyInput] = useState(" ");
const showRender = useRef(0);
const randomInput = useRef();
const toggleChange = (e) => {
setAnyInput (e.target.value);
showRender.current++;
}
const focusRandomInput = () => {
randomInput.current.focus();
}
return (
<div className="App">
<input className="TextBox"
ref ={randomInput} type="text" value={anyInput} onChange={toggleChange}
/>
<h3>Amount Of Renders: {showRender.current}</h3>
<button onClick={focusRandomInput}>Click To Focus On Input </button>
</div>
);
}
export default App;
Lägg märke till hur att skriva varje tecken i textfältet uppdaterar appens tillstånd, men aldrig utlöser en fullständig omrendering.
useImperativeHandle
Vet du hur en underordnad komponent har tillgång till anropsfunktioner som skickas till dem från den överordnade komponenten? Föräldrar skickar dem vidare via rekvisita, men den överföringen är "enkelriktad" i den meningen att föräldern inte kan anropa en funktion som finns i barnet.
Väl, useImperativeHandle
gör det möjligt för en förälder att komma åt en barnkomponents funktioner.
Hur fungerar det?
- En funktion definieras i den underordnade komponenten.
- A
ref
läggs till i föräldern. - Vi använder
forwardRef
, tillåterref
som definierades för att överföras till barnet. useImperativeHandle
exponerar barnets funktioner viaref
.
Användningsfall
useImperativeHandle
fungerar bra när man vill att en föräldrakomponent ska påverkas av förändringar hos barnet. Så saker som ett ändrat fokus, ökande och minskande och suddiga element kan vara situationer där du hittar dig själv att sträcka dig efter den här kroken så att föräldern kan uppdateras därefter.
syntax
useImperativeHandle (ref, createHandle, [dependencies])
Exempelvis
I det här exemplet har vi två knappar, en som finns i en överordnad komponent och en som är i en underordnad komponent. Genom att klicka på föräldraknappen hämtas data från barnet, vilket gör att vi kan manipulera föräldrakomponenten. Den är inställd så att ett klick på barnknappen inte skickar någonting från föräldrakomponenten till barnet för att illustrera hur vi skickar saker i motsatt riktning.
// Parent component
import React, { useRef } from "react";
import ChildComponent from "./childComponent";
import './App.css';
function useImperativeHandle() {
const controlRef = useRef(null);
return (
onClick={
() => {
controlRef.current.controlPrint();
}
}
>
Parent Box
);
}
export default useImperativeHandle;
// Child component
import React, { forwardRef, useImperativeHandle, useState } from "react";
const ChildComponent = forwardRef((props, ref) => {
const [print, setPrint] = useState(false);
useImperativeHandle(ref, () => ({
controlPrint()
{ setPrint(!print); },
})
);
return (
<>
Child Box
{ print && I am from the child component }
);
});
export default ChildComponent;
Produktion
useMemo
useMemo
är en av de minst använda men mest intressanta React-krokarna. Det kan förbättra prestandan och minska latensen, särskilt vid stora beräkningar i din app. Hur så? Varje gång en komponents tillstånd uppdateras och komponenter återrenderas, visas useMemo
krok hindrar React från att behöva räkna om värden.
Du ser, funktioner svarar på tillståndsändringar. De useMemo
krok tar en funktion och returnerar returvärdet för den funktionen. Den cachar det värdet för att förhindra att ytterligare ansträngning görs om det, och returnerar det sedan när ett av beroenden har ändrats.
Denna process kallas memoisation och det är det som hjälper till att öka prestandan genom att komma ihåg värdet från en tidigare begäran så att den kan användas igen utan att behöva upprepa all den matematiken.
Användningsfall
De bästa användningsfallen kommer att vara varje gång du arbetar med tunga beräkningar där du vill lagra värdet och använda det vid efterföljande tillståndsändringar. Det kan vara en trevlig prestationsvinst, men om du använder den för mycket kan det få raka motsatta effekter genom att appens minne försämras.
syntax
useMemo( () =>
{ // Code goes here },
[]
)
Exempelvis
När du klickar på knappen indikerar detta miniprogram när ett tal är jämnt eller udda och kvadrerar sedan värdet. Jag la till massor av nollor i slingan för att öka dess beräkningskraft. Det returnerar värdet i utspillda sekunder och fungerar fortfarande bra på grund av useMemo
krok.
// UseMemo.js
import React, { useState, useMemo } from 'react'
function Memo() {
const [memoOne, setMemoOne] = useState(0);
const incrementMemoOne = () => { setMemoOne(memoOne + 1) }
const isEven = useMemo(() => {
let i = 0 while (i < 2000000000) i++ return memoOne % 2 === 0
},
[memoOne]);
const square = useMemo(()=> {
console.log("squared the number"); for(var i=0; i < 200000000; i++);
return memoOne * memoOne;
},
[memoOne]);
return (
Memo One -
{ memoOne }
{ isEven ? 'Even' : 'Odd' } { square }
);
}
export default Memo
Produktion
useMemo
är lite som useCallback
krok, men skillnaden är den useMemo
kan lagra ett memorerat värde från en funktion, där useCallback
lagrar den lagrade funktionen själv.
useCallback
Smakämnen useCallback
Hook är en annan intressant och det sista avsnittet var en slags spoilervarning för vad den gör.
Som vi nyss såg, useCallback
fungerar som useMemo
haka på att de båda använder memoization för att cache något för senare användning. Medan useMemo
lagrar en funktions beräkning som ett cachat värde, useCallback
lagrar och returnerar en funktion.
Användningsfall
Tycka om useMemo, useCallback
är en trevlig prestandaoptimering genom att den lagrar och returnerar en memoiserad återuppringning och alla dess beroenden utan omrendering.
syntax
const getMemoizedCallback = useCallback (
() => { doSomething () }, []
);
Exempelvis
{ useCallback, useState } from "react";
import CallbackChild from "./UseCallback-Child";
import "./App.css"
export default function App() {
const [toggle, setToggle] = useState(false);
const [data, setData] = useState("I am a data that would not change at every render, thanks to the useCallback");
const returnFunction = useCallback(
(name) =>
{ return data + name; }, [data]
);
return (
onClick={() => {
setToggle(!toggle);
}}
>
{" "}
// Click To Toggle
{ toggle && h1. Toggling me no longer affects any function }
);
}
// The Child component
import React, { useEffect } from "react";
function CallbackChild(
{ returnFunction }
) {
useEffect(() =>
{ console.log("FUNCTION WAS CALLED"); },
[returnFunction]);
return { returnFunction(" Hook!") };
}
export default CallbackChild;
Produktion
Avslutande tankar
Där går vi! Vi tittade precis på fem superhändiga React-krokar som jag tror ofta förbises. Som med många roundups som denna, skrapar vi bara på ytan av dessa krokar. De har var och en sina egna nyanser och överväganden att ta hänsyn till när du använder dem. Men förhoppningsvis har du en bra uppfattning på hög nivå om vad de är och när de kanske passar bättre än en annan krok du kanske sträcker dig efter oftare.
Det bästa sättet att helt förstå dem är genom övning. Så jag uppmuntrar dig att träna på att använda dessa krokar i din ansökan för bättre förståelse. För det kan du bli mycket mer på djupet genom att kolla in följande resurser: