Hooks sind wiederverwendbare Funktionen. Sie ermöglichen es Ihnen, Zustand und andere Funktionen (z. B. Lifecycle-Methoden usw.) zu verwenden, ohne eine Klasse schreiben zu müssen. Hook-Funktionen ermöglichen es uns, in den React-Zustandslebenszyklus einzusteigen, indem wir funktionale Komponenten verwenden. So können wir den Zustand unserer funktionalen Komponenten manipulieren, ohne sie in Klassenkomponenten umwandeln zu müssen.
React führte Hooks in Version 16.8 ein und fügt seitdem weitere hinzu. Einige sind nützlicher und beliebter als andere, wie die Hooks useEffect, useState und useContext. Ich habe keinen Zweifel daran, dass Sie sich auf diese verlassen haben, wenn Sie mit React arbeiten.
Aber was mich interessiert, sind die weniger bekannten React-Hooks. Während alle React-Hooks auf ihre Weise interessant sind, gibt es fünf, die ich Ihnen wirklich zeigen möchte, weil sie Ihnen im täglichen Gebrauch vielleicht nicht begegnen – oder vielleicht doch, und das Wissen darum verleiht Ihnen zusätzliche Superkräfte.
Inhaltsverzeichnis
useReducer
Der Hook useReducer ist ein Zustandsverwaltungswerkzeug wie andere Hooks. Insbesondere ist er eine Alternative zum Hook useState.
Wenn Sie den Hook useReducer verwenden, um zwei oder mehr Zustände (oder Aktionen) zu ändern, müssen Sie diese Zustände nicht einzeln manipulieren. Der Hook verfolgt alle Zustände und verwaltet sie gemeinsam. Mit anderen Worten: Er verwaltet und rendert Zustandsänderungen neu. Im Gegensatz zum Hook useState ist useReducer einfacher, wenn es um die Verwaltung vieler Zustände in komplexen Projekten geht.
Anwendungsfälle
useReducer kann helfen, die Komplexität der Arbeit mit mehreren Zuständen zu reduzieren. Verwenden Sie ihn, wenn Sie mehrere Zustände gemeinsam verfolgen müssen, da er es Ihnen ermöglicht, die Zustandsverwaltung und die Rendering-Logik einer Komponente als separate Belange zu behandeln.
Syntax
useReducer akzeptiert drei Argumente, von denen eines optional ist
- eine Reducer-Funktion
initialState- eine
init-Funktion (optional)
const [state, dispatch] = useReducer(reducer, initialState)
const [state, dispatch] = useReducer(reducer, initialState initFunction) // in the case where you initialize with the optional 3rd argument
Beispiel
Das folgende Beispiel ist eine Oberfläche, die ein Texteingabefeld, einen Zähler und einen Button enthält. Die Interaktion mit jedem Element aktualisiert den Zustand. Beachten Sie, wie useReducer es uns ermöglicht, mehrere Fälle auf einmal zu definieren, anstatt sie einzeln einzurichten.
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;
Aus dem obigen Code sehen Sie, wie wir mehrere Zustände einfach im Reducer (switch-case) verwalten können. Dies zeigt den Vorteil von useReducer. Das ist die Macht, die er uns gibt, wenn wir in komplexen Anwendungen mit mehreren Zuständen arbeiten.
useRef
Der Hook useRef wird verwendet, um Refs auf Elemente zu erstellen, um auf das DOM zuzugreifen. Aber mehr noch, er gibt ein Objekt mit einer .current-Eigenschaft zurück, die während des gesamten Lebenszyklus einer Komponente verwendet werden kann. So bleiben Daten erhalten, ohne einen erneuten Render auszulösen. Der Wert von useRef bleibt also zwischen den Renderings gleich; die Aktualisierung der Referenz löst keinen erneuten Render aus.
Anwendungsfälle
Greifen Sie zum Hook useRef, wenn Sie
- das DOM mit gespeicherten veränderlichen Informationen manipulieren möchten.
- auf Informationen aus untergeordneten Komponenten (verschachtelte Elemente) zugreifen möchten.
- den Fokus auf ein Element setzen möchten.
Er ist am nützlichsten, wenn Sie veränderliche Daten in Ihrer App speichern möchten, ohne einen erneuten Render auszulösen.
Syntax
useRef akzeptiert nur ein Argument, nämlich den Anfangswert.
const newRefComponent = useRef(initialValue);
Beispiel
Hier habe ich den Hook useRef und useState verwendet, um zu zeigen, wie oft eine Anwendung einen aktualisierten Zustand rendert, wenn in ein Texteingabefeld getippt wird.
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;
Beachten Sie, wie jeder Buchstabe, der in das Textfeld eingegeben wird, den Zustand der App aktualisiert, aber niemals einen vollständigen erneuten Render auslöst.
useImperativeHandle
Sie wissen, wie eine untergeordnete Komponente Funktionen aufrufen kann, die von der übergeordneten Komponente an sie übergeben wurden? Übergeordnete Komponenten geben diese über Props weiter, aber diese Weitergabe ist "unidirektional" in dem Sinne, dass die übergeordnete Komponente keine Funktion aufrufen kann, die sich in der untergeordneten Komponente befindet.
Nun, useImperativeHandle ermöglicht es einer übergeordneten Komponente, auf Funktionen einer untergeordneten Komponente zuzugreifen.
Wie funktioniert das?
- Eine Funktion wird in der untergeordneten Komponente definiert.
- In der übergeordneten Komponente wird ein
refhinzugefügt. - Wir verwenden
forwardRef, wodurch der definierterefan die untergeordnete Komponente weitergegeben werden kann. useImperativeHandlestellt die Funktionen der untergeordneten Komponente über denrefbereit.
Anwendungsfälle
useImperativeHandle funktioniert gut, wenn Sie möchten, dass eine übergeordnete Komponente von Änderungen in der untergeordneten Komponente beeinflusst wird. Dinge wie ein geänderter Fokus, Inkrementieren und Dekrementieren sowie ausgeblendete Elemente können Situationen sein, in denen Sie diesen Hook verwenden, damit die übergeordnete Komponente entsprechend aktualisiert werden kann.
Syntax
useImperativeHandle (ref, createHandle, [dependencies])
Beispiel
In diesem Beispiel haben wir zwei Buttons, einen in einer übergeordneten Komponente und einen in einer untergeordneten. Das Klicken auf den übergeordneten Button ruft Daten aus der untergeordneten Komponente ab und ermöglicht uns, die übergeordnete Komponente zu manipulieren. Es ist so eingerichtet, dass das Klicken auf den untergeordneten Button nichts von der übergeordneten Komponente an die untergeordnete Komponente weitergibt, um zu veranschaulichen, wie wir Dinge in die entgegengesetzte Richtung übergeben.
// 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;
Ausgabe
useMemo
useMemo ist einer der am seltensten verwendeten, aber interessantesten React-Hooks. Er kann die Leistung verbessern und die Latenz verringern, insbesondere bei großen Berechnungen in Ihrer App. Wie das geht? Jedes Mal, wenn sich der Zustand einer Komponente aktualisiert und Komponenten neu gerendert werden, verhindert der Hook useMemo, dass React Werte neu berechnen muss.
Sehen Sie, Funktionen reagieren auf Zustandsänderungen. Der Hook useMemo nimmt eine Funktion und **gibt den Rückgabewert dieser Funktion zurück**. Er speichert diesen Wert zwischen, um zu verhindern, dass zusätzliche Anstrengungen für die Neudefinition aufgewendet werden, und gibt ihn dann zurück, wenn sich eine der Abhängigkeiten geändert hat.
Dieser Prozess wird als Memoisation bezeichnet und hilft, die Leistung zu steigern, indem der Wert aus einer früheren Anfrage gespeichert wird, damit er wiederverwendet werden kann, ohne all die Berechnungen zu wiederholen.
Anwendungsfälle
Die besten Anwendungsfälle sind immer dann, wenn Sie mit rechenintensiven Berechnungen arbeiten, bei denen Sie den Wert speichern und bei nachfolgenden Zustandsänderungen verwenden möchten. Es kann ein schöner Leistungsgewinn sein, aber zu viel davon zu verwenden, kann genau den gegenteiligen Effekt haben, indem es den Speicher Ihrer App belastet.
Syntax
useMemo( () =>
{ // Code goes here },
[]
)
Beispiel
Beim Klicken auf den Button zeigt dieses Mini-Programm an, ob eine Zahl gerade oder ungerade ist, und quadriert dann den Wert. Ich habe viele Nullen zur Schleife hinzugefügt, um ihre Rechenleistung zu erhöhen. Sie gibt den Wert in Sekundenschnelle zurück und funktioniert dank des Hooks useMemo immer noch gut.
// 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
Ausgabe
useMemo ist ein wenig wie der Hook useCallback, aber der Unterschied ist, dass useMemo einen gemerzeten Wert aus einer Funktion speichern kann, während useCallback die gemerzete Funktion selbst speichert.
useCallback
Der Hook useCallback ist ein weiterer interessanter Hook, und der letzte Abschnitt war eine Art Spoiler-Alarm für das, was er tut.
Wie wir gerade gesehen haben, funktioniert useCallback wie der Hook useMemo, da beide Memoisation verwenden, um etwas für die spätere Verwendung zu cachen. Während useMemo die Berechnung einer Funktion als gecachten Wert speichert, speichert und gibt useCallback eine Funktion zurück.
Anwendungsfälle
Wie useMemo ist useCallback eine schöne Leistungsoptimierung, da es einen gemerzeten Callback und seine Abhängigkeiten ohne erneuten Render speichert und zurückgibt.
Syntax
const getMemoizedCallback = useCallback (
() => { doSomething () }, []
);
Beispiel
{ 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;
Ausgabe
Abschließende Gedanken
Da haben wir's! Wir haben uns fünf super praktische React-Hooks angesehen, die meiner Meinung nach oft übersehen werden. Wie bei vielen Zusammenfassungen dieser Art kratzen wir hier nur an der Oberfläche dieser Hooks. Jeder von ihnen hat seine eigenen Nuancen und Überlegungen, die man bei der Verwendung berücksichtigen muss. Aber hoffentlich haben Sie eine gute High-Level-Vorstellung davon, was sie sind und wann sie besser passen könnten als ein anderer Hook, zu dem Sie vielleicht öfter greifen.
Der beste Weg, sie vollständig zu verstehen, ist durch Übung. Deshalb ermutige ich Sie, diese Hooks in Ihrer Anwendung zu üben, um sie besser zu verstehen. Dazu können Sie tiefer eintauchen, indem Sie die folgenden Ressourcen konsultieren
- Einführung in React Hooks (Kingsley Silas)
- Hooks im Überblick (React-Dokumentation)
- Hooks-Spickzettel (Ohans Emmanuel)
- Der Kreis eines React-Lebenszyklus (Kingsley Silas)
- Hooks von React Router (Agney Menon)
- Testen von React Hooks mit Enzyme und React Testing Library (Kingsley Silas)
Danke für das Aufschreiben! Es gibt neue offizielle React-Dokumente, die React Hooks zuerst auf beta.reactjs.org lehren. Schauen Sie sie sich an!
Danke, Rachel. Das werde ich tun!
Die React-Dokumentation besagt, dass useMemo nur zur Optimierung dient und nicht garantiert, dass es niemals neu berechnet.
Wie würden Sie es implementieren, wenn Sie möchten, dass es nicht neu berechnet wird (z.B. wenn es Zufallswerte verwendet)? Würden Sie
useRefverwenden? Oder vielleicht den Anfangswert vonuseState(obwohl es kein Zustand ist)? Ich konnte keine natürliche Methode finden.Was meinen Sie im useRef-Beispiel mit "vollständigem erneuten Rendern"? Bei jeder Eingabe steigt die Anzahl der Renderings im Beispiel, also wie unterscheidet es sich?
Danke für das Teilen! Ich glaube, ich muss eine Datei in meinem Codebase refaktorisieren, um den useReducer Hook zu nutzen, denn der aktuelle Zustand ist sehr umfangreich.
Eine Frage: Beim useImperativeHandle Hook habe ich bemerkt, dass der an die untergeordnete Komponente übergebene
refnicht als Attribut zu einem der Elemente der untergeordneten Komponente hinzugefügt wird.Bedeutet dies also mit der
forwardRefFunktion, dass alle Elemente der untergeordneten Komponente über den ref Hook in der übergeordneten Komponente referenziert werden, oder wird nur die FunktioncontrolPrint(), die demuseImperativeHandleHook hinzugefügt wurde, referenziert?Danke für das Teilen des Artikels.
Ich bin mir jedoch nicht sicher, ob das useMemo-Codeabschnittsbeispiel tatsächlich wie beabsichtigt implementiert wurde, um zu demonstrieren, dass die useMemo-Callbacks (x2) nicht neu berechnet werden sollen, sondern stattdessen gecachte Werte zurückgeben sollen.
Wie Sie sehen, ist useMemo in beiden Fällen von Änderungen an der Variable "count" im aktuellen Codebeispiel abhängig. Die Variable "count" wird bei jedem Klick auf den Button "Memo One" (über "setCount()") aktualisiert, und daher werden die Callbacks innerhalb der useMemo-Funktionen bei jedem Klick neu berechnet.
Würde das nicht den Zweck verfehlen, zu demonstrieren, dass useMemo den gecachten Wert zurückgeben sollte, anstatt bei jedem Klick kontinuierlich neu zu berechnen?
Oder verstehe ich etwas falsch?
Ich habe einen Tippfehler in meiner ursprünglichen Antwort bemerkt... also anstatt
„count“ und „setCount()“, meine ich „memoOne“ und „setMemoOne()“
Kann ein Administrator oder Benutzer mir sagen, wie der Code in WordPress auf CSS Tricks angezeigt wird, ich meine, ist es im Vergleich zu jedem Plugin oder direkt im Vergleich zu PHP-Code? Bitte.
Chris hat hier einen Beitrag dazu: https://css-tricks.de/posting-code-blocks-wordpress-site/