
Guten Tag, Chabrowsk!
Ich möchte darüber sprechen, wie ich kürzlich in React von bestimmten „Hooks“ erfahren habe. Sie erschienen vor relativ kurzer Zeit in der Version [16.8.0] vom 6. Februar 2019 (die nach den Entwicklungsgeschwindigkeiten von FrontEnd bereits sehr lange zurückliegt).
Nachdem ich die Dokumentation gelesen hatte , konzentrierte ich mich auf den useReducer- Hook und stellte mir sofort die Frage: "Dieses Ding kann Redux komplett ersetzen !?" Ich habe mehrere Abende mit Experimenten verbracht und möchte nun die Ergebnisse und meine Schlussfolgerungen teilen.
Muss ich Redux durch useContext + useReducer ersetzen?
Für die ungeduldigen - sofort Schlussfolgerungen
Für:
- Sie können Hooks (useContext + useReducer) anstelle von Redux in kleinen Anwendungen verwenden (wo keine großen kombinierten Reduzierer erforderlich sind). In diesem Fall kann Redux tatsächlich redundant sein.
Gegen:
- Auf einer Reihe von React + Redux wurde bereits eine große Menge Code geschrieben, und es erscheint zumindest vorerst nicht ratsam, ihn in Hooks (useContext + useReducer) umzuschreiben.
- Redux ist eine bewährte Bibliothek, Hooks sind eine Innovation, ihre Schnittstellen und ihr Verhalten können sich in Zukunft ändern.
- Um die Verwendung von useContext + useReducer wirklich bequem zu gestalten, müssen Sie einige Fahrräder schreiben.
Die Schlussfolgerungen sind die persönliche Meinung des Autors und erheben keinen Anspruch auf bedingungslose Wahrheit. Wenn Sie nicht einverstanden sind, freue ich mich über Ihre konstruktive Kritik in den Kommentaren.
Versuchen wir es herauszufinden
Beginnen wir mit einem einfachen Beispiel.
(reducer.js)
import React from "react"; export const ContextApp = React.createContext(); export const initialState = { app: { test: 'test_context' } }; export const testReducer = (state, action) => { switch(action.type) { case 'test_update': return { ...state, ...action.payload }; default: return state } };
Bisher sieht unser Reduzierer genauso aus wie bei Redux
(app.js)
import React, {useReducer} from 'react' import {ContextApp, initialState, testReducer} from "./reducer.js"; import {IndexComponent} from "./IndexComponent.js" export const App = () => {
(IndexComponent.js)
import React, {useContext} from "react"; import {ContextApp} from "./reducer.js"; export function IndexComponent() {
Dies ist das einfachste Beispiel, in dem wir einfach Update Schreiben Sie neue Daten in einen flachen Reduzierer (ohne Verschachtelung)
Theoretisch können Sie sogar versuchen, so zu schreiben:
(reducer.js)
... export const testReducer = (state, data) => { return { ...state, ...data } ...
(IndexComponent.js)
... return (
Wenn wir keine große und einfache Anwendung haben (was in der Realität selten der Fall ist), können Sie den Typ nicht verwenden und Reduzierungsaktualisierungen immer direkt aus der Aktion heraus verwalten. Übrigens haben wir auf Kosten von Updates in diesem Fall nur neue Daten in Reducer geschrieben, aber was ist, wenn wir einen Wert in einem Baum mit mehreren Verschachtelungsebenen ändern müssen?
Jetzt komplizierter
Schauen wir uns das folgende Beispiel an:
(IndexComponent.js)
... return (
(reducer.js)
... export const initialState = { tree_1: { tree_2_1: { tree_3_1: 'tree_3_1', tree_3_2: 'tree_3_2' }, tree_2_2: { tree_3_3: 'tree_3_3', tree_3_4: 'tree_3_4' } } }; export const testReducer = (state, callback) => {
Okay, wir haben auch das Baum-Update herausgefunden. In diesem Fall ist es jedoch bereits besser, wieder Typen in testReducer zu verwenden und den Baum gemäß einer bestimmten Art von Aktion zu aktualisieren. Alles ist wie in Redux, nur das resultierende Bündel ist etwas kleiner [8].
Asynchrone Operationen und Versand
Aber ist alles in Ordnung? Was passiert, wenn wir asynchrone Operationen verwenden?
Dazu müssen wir unseren eigenen Versand definieren. Lass es uns versuchen!
(action.js)
export const actions = { sendToServer: function ({dataForServer}) {
(IndexComponent.js)
const [state, _dispatch] = useReducer(AppReducer, AppInitialState);
Alles scheint auch in Ordnung zu sein, aber jetzt haben wir viele Callback-Verschachtelungen , was nicht sehr cool ist. Wenn wir nur den Status ändern wollen, ohne eine Aktionsfunktion zu erstellen, müssen wir eine Konstruktion dieser Art schreiben:
(IndexComponent.js)
... dispatch( (dispatch) => dispatch(state => { return { {dataForServer: 'data'} } }) ) ...
Es stellt sich heraus, dass etwas beängstigend ist, oder? Für ein einfaches Datenupdate möchte ich wirklich so etwas schreiben:
(IndexComponent.js)
... dispatch({dataForServer: 'data'}) ...
Dazu müssen Sie den Proxy für die zuvor erstellte Versandfunktion ändern
(IndexComponent.js)
const [state, _dispatch] = useReducer(AppReducer, AppInitialState);
Jetzt können wir sowohl eine Aktionsfunktion als auch ein einfaches Objekt zum Versenden übergeben.
Aber! Bei einer einfachen Übertragung des Objekts müssen Sie vorsichtig sein, Sie könnten versucht sein, dies zu tun:
(IndexComponent.js)
... dispatch({ tree: {
Warum ist dieses Beispiel schlecht? Durch die Tatsache, dass zum Zeitpunkt der Verarbeitung dieses Versands der Status möglicherweise durch einen anderen Versand aktualisiert wurde, diese Änderungen jedoch noch nicht unsere Komponente erreicht haben, verwenden wir tatsächlich eine alte Statusinstanz, die alles mit alten Daten überschreibt.
Aus diesem Grund ist eine solche Methode kaum geeignet, nur um flache Reduzierungen zu aktualisieren, bei denen keine Verschachtelung vorliegt und Sie den Status nicht zum Aktualisieren verschachtelter Objekte verwenden müssen. In der Realität sind Reduzierungen selten perfekt flach, daher würde ich Ihnen raten, diese Methode überhaupt nicht zu verwenden und Daten nur durch Aktionen zu aktualisieren.
(action.js)
...
Schlussfolgerungen:
- Es war eine interessante Erfahrung, ich vertiefte mein akademisches Wissen und lernte neue Merkmale der Reaktion
- Ich werde diesen Ansatz nicht in der Produktion anwenden (zumindest in den nächsten sechs Monaten). Aus den oben bereits beschriebenen Gründen (dies ist eine neue Funktion und Redux ist ein bewährtes und zuverlässiges Tool) + Ich habe keine Leistungsprobleme, die ich nach den Millisekunden verfolgen muss, die Sie gewinnen können, wenn Sie den Editor verlassen. [8]
Ich werde mich freuen, in den Kommentaren die Meinung von Kollegen aus dem Front-End-Teil unserer Habrosobschestva zu erfahren!
Referenzen: