Redux: RFC: Redux-Starterkit

Erstellt am 1. März 2018  ·  56Kommentare  ·  Quelle: reduxjs/redux

Basierend auf den Kommentaren in #2858 und früher in #2295 klingt es wie ein vorkonfiguriertes Starterkit aus Redux-Kern + einiger allgemeiner Middleware + Store-Enhancern + anderen Tools, die hilfreich sein könnten, um mit der Bibliothek zu beginnen.

Ich habe damit begonnen, einen Paketnamen zu reservieren (aber ich bin nicht fest darauf eingestellt) und wir können damit beginnen, die Lücken dort auszufüllen. Ich möchte den Inhalt dieses Pakets hier pflegen, damit wir kein weiteres Repo oder ähnliches einrichten müssen. Wir möchten vielleicht ein Monorepo untersuchen, aber ich glaube nicht, dass es derzeit einen dringenden Bedarf gibt.

Eine Sache möchte ich gleichzeitig untersuchen: combineReducers in ein eigenes Paket aufzuteilen. Es ist die eine Sache, die vorgeschrieben wird, wie man einen Laden strukturiert und betreibt. Es ist offensichtlich nicht der einzige Weg, aber ich fürchte, viele Leute sehen nicht darüber hinweg.

Was in einem Starterpaket enthalten ist, enthält meiner Meinung nach eine der Boilerplate-Reduktionsbibliotheken (oder etwas, das wir bauen), beliebte Middleware wie Thunks und Sagas und hilfreiche Entwicklungstools. Wir könnten ein Teilmengenpaket für React-spezifische Benutzer haben. Tatsächlich habe ich eine Twitter-Umfrage gestartet, um herauszufinden, ob das überhaupt notwendig ist (bitte RT!).

Ich glaube nicht, dass wir mit einem CLI-Tool und all dem Jazz eine Create React App-ähnliche Erfahrung erstellen müssen. Aber etwas Out-of-the-Box, das eine großartige Entwicklererfahrung mit besserem Debugging und weniger Code bietet.

discussion ecosystem feedback wanted

Hilfreichster Kommentar

Also, äh... Ich ging und tat etwas:

Dinge, die sich vom vorherigen Snippet unterscheiden:

  • Ich habe eine enhancers Konfigurationsoption eingefügt, nur weil
  • Ich habe die Abhängigkeit selectorator hinzugefügt und createSelector exportiert

Die Gedanken?

Alle 56 Kommentare

JA JA JA! ICH HABE VIELE MEINUNGEN UND WÜNSCHE DAFÜR! Aber ich halte mich zurück und lasse die Diskussion erst einmal in Gang kommen.

Ein Wunschlistenpunkt, den ich hätte, von dem ich nicht sicher bin, ob er machbar ist, ist der integrierte HMR für Reduzierstücke, der automatisch in einer createReduxStore() -Funktion hinzugefügt wird. Leider sagt mein Wissen über Webpack und einige Experimente, dass dies nicht sehr machbar ist, da Sie in den Webpack- module.hot.accept() Callbacks hartcodierte Pfade zu den Reducer-Dateien haben müssen. Ich bin mir nicht sicher, wie Parcel oder andere Bundler damit umgehen.

Also, erste Bitte um Feedback von allen:

  • Was sind die wichtigsten Anforderungen, die wir mit diesem Paket erfüllen möchten?
  • Welche _vorhandenen_ Pakete würden Sie vorschlagen, um diese Anforderungen zu erfüllen?
  • Wie können wir diese Pakete am besten kombinieren, um die Dinge für den Endbenutzer einfach zu halten?

Nennen wir 3 wichtige Punkte, wobei mögliche Varianten voneinander _isoliert_ werden.

  1. Erster Punkt. Reduzierer-Manager
    1.0 Vanille (ist das hier der Fall?)
    1.1 Immer.js
    1.2 Coreux
    1.3 100500 weitere Pakete

  2. Zweiter Punkt. Middleware
    2.0 Vanille (ist das der Fall?)
    2.1 Sagen
    2.2 Epen
    2.3 100500 weitere Pakete.

  3. Dritter Punkt. Reaktionsintegration
    3.0. Vanille (ist das hier der Fall?)
    3.1. Unterraum
    3.2 Restaurieren
    3.3 100500 weitere Pakete.

4., Bonus, Punkt
4.0 Das ganze Zeug in einer _Boilerplate_ testen.

Es ist unmöglich, "die Auserwählten" auszuwählen, zum Beispiel ich liebe und verwende sowohl Sagas als auch Epics, aber es ist möglich, einige "Kochbelege" und Empfehlungen für Kombinationen bereitzustellen.

Zum Beispiel kennen die meisten Redux-Benutzer __nur__ Middleware. Ein kleiner Teil macht auch etwas mit Reducern (ok viel _gehört_ über immutable.js), nur ein paar verbessern die React-Integration.

Starter Kit könnte nur helfen, von Anfang an einen vollständigen und _reichen_ Ansatz zu entwickeln. Oder man braucht mehr als ein Starter Kit.

Auf Twitter um Feedback zu Setup/Boilerplate Pain Points gebeten: https://twitter.com/acemarke/status/969040835508604929

Kopiere meine Antwort auf Twitter:

Ich habe mich ausdrücklich davon ferngehalten, Redux-Boilerplate hinzuzufügen, da es IMO die Komplexität erhöht, wenn Sie "Ihre Art", Redux einer anderen Person vorzustellen, vorstellen. Ich würde mir mehr präskriptive Konventionen wünschen, die per Code erzwungen werden, um Redux zu einer tragbareren Fähigkeit zu machen.

Zu diesem Zweck würde ein Repo im Stil von create-redux-app - jedoch eher als Bibliothek denn als Framework konzipiert - insbesondere eines, das von Redux-Betreuern der besten und empfohlenen Praktiken ausdrücklich befürwortet wird, meiner Meinung nach einen großen Beitrag zur Festigung und Verbesserung der Klarheit leisten bei richtiger Redux-Nutzung.

Wir haben auf Reactiflux ein wenig darüber gesprochen, wollten eine Konsolidierung von Wünschen zur Aufnahme in diesen Thread kopieren, einige davon überschneiden sich mit den Punkten, die Sie bereits @timdorr aufgelistet

  1. Wrapper um createStore mit besseren Standardeinstellungen, dh einfachere Möglichkeit zum Hinzufügen von Middleware, Redux-Entwicklungstools
  2. eingebauter unveränderlicher Helfer (immer?)
  3. createReducer integriert (das Standard-Dienstprogramm "Reducer Lookup Table")
  4. Integriert neu auswählen
  5. Aktionsersteller, der sich an FSA hält
  6. Unterstützung von asynchronen Aktionen / Unterstützung von Nebeneffekten (Fluss, Saga, was?)

Warum nicht offiziell etwas unterstützen, das bereits existiert, wie Henrik Joretegs Redux-Bundler?

https://github.com/HenrikJoreteg/redux-bundler

Es ist prägnant, rechthaberisch (auf eine gute Art), ermöglicht die Wiederverwendung von Redux-bezogenen Funktionen über Anwendungen hinweg und bietet dennoch eine schöne Lösung für die asynchrone Handhabung.

Es ist ein faszinierend aussehendes Projekt, das ich wirklich weiter untersuchen möchte, aber es ist auch außerhalb des Rahmens für das, was ich mit dieser Aufgabe machen möchte.

Was ich hier wirklich erreichen möchte ist:

  • Einrichten eines Redux-Stores mit ein paar Codezeilen und minimalen Konfigurationsoptionen (das Redux-Äquivalent des "zero-config JS"-Slogans, den Webpack und Parcel verwendet haben).
  • Ähnlich wie bei CRA ist Config-Zeug im Grunde versteckt, mit guten Standardeinstellungen
  • Einbeziehung sorgfältig ausgewählter Pakete, um die Entwicklererfahrung zu verbessern und, ja, "Boilerplate zu reduzieren". Zum Beispiel wäre Immer eine gute Wahl, weil es das Schreiben unveränderlicher Reduzierlogik drastisch vereinfacht _und_ Ihren Zustand in dev einfriert. (Mein einziges Zögern ist, dass das Aussehen von Code, der "mutiert", verwirrend wäre.)

Ich möchte diese Bemühungen ziemlich eng gefasst halten. Ich habe in den letzten Stunden mit @hswolff und @nickmccurdy in Reactiflux gechattet, und obwohl die Diskussion großartig war, haben wir bereits ein Dutzend sich überschneidender Anwendungsfälle und Ideen durchgespielt, die die Dinge wirklich kompliziert machen könnten.

Ich möchte _etwas_ Nützliches, Wertvolles und Machbares zusammenstellen, ohne zu viel Fahrradabwurf zu machen, und dann andere Diskussionen nebenher führen (wie eine API zum Erstellen von Redux-Bündeln oder -Modulen usw.).

Um einige anfängliche Boilerplating von APIs zu starten, hier eine grundlegende Idee für 1-3 meiner Liste, die ich oben gepostet habe:

// #1
export function createStore({
    // If an object is given it's passed to combineReducers
    // otherwise it's just used directly.
    reducer: Object<String, Function> | Function,
    // Middleware is built-in and accepts an array of middleware functions.
    middleware: Array<MiddlewareFunction>,
    // Built-in support for devtools.
    // Defaults to NODE_ENV !== production
    devTools: boolean,
    // Same as current createStore.
    preloadedState,
    // Same as current createStore.
    enhancer,
}) {};

// Re-exported for easy usage.
export function combineReducers() {}

// #2
// Re-export immer as the built-in immutability helper.
import immer from 'immer';
export const createNextState = immer;

// #3
// Export an already written version of createReducer .
// Same thing as https://redux.js.org/recipes/structuring-reducers/refactoring-reducers-example#reducing-boilerplate
export function createReducer() {}

Ja, das grabe ich. Ich würde dann erwarten, dass entweder immer thunk() am Anfang der Middleware-Liste hinzugefügt wird oder möglicherweise nur, wenn Sie selbst keine Middleware bereitgestellt haben. Möglicherweise möchten wir dem Benutzer nicht einmal erlauben, hier Enhancer anzugeben. Wir würden applyMiddleware() automatisch hinzufügen, wenn Middleware vorhanden ist, und die Funktion composeWithDevtools von redux-devtools-extension wenn devTools : true . Für diese "einfache Einrichtung" denke ich, dass wir "Verbesserer" aus den Dingen eliminieren möchten, die der Benutzer konfigurieren kann.

+1 für das Eliminieren von Verstärkern.

Wenn Sie denken, dass es automatisch hinzugefügt wird, sollten wir in der Lage sein, unseren Kuchen zu haben und ihn auch zu essen, indem wir die Funktion exportieren, die wir verwenden würden, um die Standard-Middleware hinzuzufügen:

export function createDefaultMiddleware(...additional) {
    return [thunk(), ...additional],
}

// Within a user's application
createStore({
    // By default it's just createDefaultMiddleware()
    // However if you want to add any other middleware you can.
    middleware: createDefaultMiddleware(any, other, middleware)
})

Ja, ungefähr das habe ich mir gedacht. Mein Hauptanliegen ist es herauszufinden, ob der Benutzer versehentlich versucht, seine eigene Instanz von thunk .

Ich beschloss, heute Abend ein bisschen mit den Dingen herumzuspielen. Hier ist ein erster Schnitt. Die Gedanken?

// configureStore.js
import {createStore, compose, applyMiddleware, combineReducers} from "redux";
import { composeWithDevTools } from 'redux-devtools-extension';
import createNextState from "immer";

import isPlainObject from "./isPlainObject";

import thunk from "redux-thunk";


const IS_DEVELOPMENT = process.env.NODE_ENV !== "production";

export function createDefaultMiddleware(...additional) {
    return [thunk, ...additional];
}

export function configureStore(options = {}) {
    const {
        reducer,
        middleware = createDefaultMiddleware(),
        devTools = IS_DEVELOPMENT,
        preloadedState,
    } = options;

    let rootReducer;

    if(typeof reducer === "function") {
        rootReducer = reducer;
    }
    else if(isPlainObject(reducer)) {
        rootReducer = combineReducers(reducer);
    }
    else {
        throw new Error("Reducer argument must be a function or an object of functions that can be passed to combineReducers");
    }

    const middlewareEnhancer = applyMiddleware(...middleware);

    const storeEnhancers = [middlewareEnhancer];

    let finalCompose = devTools ? composeWithDevTools : compose;

    const composedEnhancer = finalCompose(...storeEnhancers);

    const store = createStore(
        rootReducer,
        preloadedState,
        composedEnhancer
    );

    return store;
}

export function createReducer(initialState, actionsMap) {
    return function(state = initialState, action) {
        const {type, payload} = action;

        return createNextState(state, draft => {
            const caseReducer = actionsMap[type];

            if(caseReducer) {
                return caseReducer(draft, payload);
            }

            return draft;
        });
    }
}
export {createNextState, combineReducers};

Und die obligatorische Beispiel-Todo-App:

import {configureStore, createReducer} from "./configureStore";

const ADD_TODO = "ADD_TODO";
const TOGGLE_TODO = "TOGGLE_TODO";
const SET_VISIBILITY_FILTER = "SET_VISIBILITY_FILTER";

function setVisibility(state, newFilterType) {
    return newFilterType;
}

const visibilityReducer = createReducer("SHOW_ALL", {
    [SET_VISIBILITY_FILTER] : setVisibility
});


function addTodo(state, newTodo) {
    state.push({...newTodo, completed : false});
}

function toggleTodo(state, payload) {
    const {index} = payload;

    const todo = state[index];
    todo.completed = !todo.completed;
}

const todosReducer = createReducer([], {
    [ADD_TODO] : addTodo,
    [TOGGLE_TODO] : toggleTodo
});


const preloadedState = {
    todos: [{
        text: 'Eat food',
        completed: true
    }, {
        text: 'Exercise',
        completed: false
    }],
    visibilityFilter : 'SHOW_COMPLETED'
};


const store = configureStore({
    reducer : {
        todos : todosReducer,
        visibilityFilter : visibilityReducer,
    },
    preloadedState,
});

const exercise1 = store.getState().todos[1];

store.dispatch({type : "TOGGLE_TODO", payload : {index : 1}});

const exercise2 = store.getState().todos[1];

console.log("Same object: ", exercise1 === exercise2);

store.dispatch({type : "SET_VISIBILITY_FILTER", payload : "SHOW_COMPLETED"});

console.log(store.getState());

Ich denke, dies ist ein solider Anfang und ein großartiger Anfang für die Lib, die in diesem Thread diskutiert wird. Es deckt die Punkte 1, 2 , 3 und 6 aus meiner obigen

Darüber zu iterieren wäre großartig, aber dies ist eine solide Grundlage.

Anstatt uns auf die Implementierung zu konzentrieren, möchte ich, dass wir uns auf den DX konzentrieren. Was sind die Exporte/APIs und wie werden sie verwendet? Ich denke, es ist eine großartige Gelegenheit, nur die Konfiguration zu überwinden und auch zu sehen, wie die Leute den Laden nutzen. Einige zufällige Ideen:

Einfachere Reduzierer/Aktions-Paare:

Machen Sie es ganz einfach, Ihre Reduzierer und Aktionen zusammen mit ihrer Statusausgabe zu koppeln. Das ist grob, aber hier ist die Grundidee:

import { createStore, createActionPack, combineActionPacks } from 'redux/starter'

const counter = createActionPack({
  increment: counter => counter + 1,
  decrement: counter => counter - 1,
  set: (_, value) => value
}, 0)

const posts = createActionPack({
  load: async () => await fetch('/posts'),
  create: async (state, text) => state.push(await fetch('/posts/new', { body: { text } }))
}, [])

const store = createStore(
  combineActionPacks(
    counter,
    posts
  )
)

store.dispatch(counter.increment())
store.dispatch(counter.set(42))

await store.dispatch(posts.load())
await store.dispatch(posts.create('First!'))

Shop Singleton

Dieses hier bin ich keineswegs verkauft, aber ich dachte zurück an die Tage, als wir historische Singletons in React Router hatten. Es war nicht perfekt, aber es bot einen gewissen Wert.

import { store, configureStore } from 'redux/starter'

configureStore(reducer, middleware, initialState)

store.dispatch(someAction())
store.getState()

Konfigurierbarkeit über import

Ich hebe meine verrücktesten zum Schluss auf. Aber was wäre, wenn wir die Konfiguration durch Importieren von Dateien zulassen würden. Wir bräuchten hinter den Kulissen etwas Global Passing, was chaotisch / mühsam wird. Aber auch hier steht der Benutzer im Mittelpunkt, nicht unsere Seite.

import { createStore } from 'redux/starter'
import 'redux/starter/devtools'
import 'redux/starter/logger'
import 'redux/starter/immutable'

// OR!

import { createStore } from 'redux/starter/developer'
import { createStore } from 'redux/starter/production'

Für dieses zweite Beispiel kann ich sehen, dass Benutzer entweder in ihren Build-Tools einen Alias ​​auf dieses Paket anwenden oder etwas wie React tun.

Okay, das war's erstmal von mir. Auch hier möchte ich an den Benutzer zuerst denken. Welche schmutzigen, hässlichen Hacks wir auch immer machen müssen, um dies zu implementieren, ist irrelevant. Der springende Punkt ist ein großartiger DX mit weniger geschriebenem Code und weniger Konfigurationsaufwand.

Liebe diese Ideen bisher. Mein einziger Wunsch für das, was sich herausstellt, wäre ein anmutiger Zugriff auf die niedrigere Standard-Redux-API. Es muss einen natürlichen Weg geben, den Menschen anpassen oder auswerfen können. Ob das in ein paar Tagen oder ein oder zwei Jahren ist, es sollte einfach sein. Lock-in ist eines der Probleme, die ich sehe (aus meinem eigenen Versuch mit Jumpstate und aus neueren Bibliotheken wie Rematch). Je mehr wir das vermeiden können, desto besser schmecken die Leute im Mund :)

Ja, ich habe einige Util-Bibliotheken gesehen, die so etwas wie dieses "Action Pack" machen (zumindest was den Aspekt "Schreibe einige Reduzierer, verwandle die Schlüssel in Action-Typen und Action-Ersteller" an) und ich habe überlegt, zu werfen das als zusätzliches Element - war nur noch nicht angekommen. Beim Aspekt "combineActionPack" bin ich mir nicht sicher.

Hatte letzte Nacht eine zusätzliche Diskussion mit @hswolff . Ich würde gerne die Selektorbibliothek hinzufügen/reexportieren, die eine Obermenge der Reselect-API mit einigen zusätzlichen nützlichen Vorteilen zu sein scheint:

import createSelector from 'selectorator';

// selector created with single method call
const getBarBaz = createSelector(['foo.bar', 'baz'], (bar, baz) => {
  return `${bar} ${baz}`;
});

Das würde helfen, viele der handgeschriebenen "einfachen Eingabe"-Selektoren wie const selectTodos = state => state.todos .

Ich bin mir nicht sicher, ob ich den Vorteil des Hinzufügens einer Selektorbibliothek sehe. Wir müssten auch eine Meinung über die dadurch ermöglichte Staatsform abgeben.

Es ist zumindest teilweise nur so, dass der Benutzer ein Element weniger in package.json installieren muss.

Ich denke, eine Auswahlbibliothek wäre großartig.

Ebenfalls relevant: der aktuelle Artikel zum apollo-boost Starterkit

Wenn wir die API von react-redux connect , um reselect (oder eine ähnliche Selektorbibliothek) zu verwenden, wenn mapStateToProps ein Array , könnten wir fördern die Verwendung von Selektoren und machen es sehr bequem, ohne die Kompatibilität zu beeinträchtigen. Ich denke nicht, dass diese Bibliothek unbedingt mit React oder react-redux gekoppelt werden sollte, aber vielleicht könnten wir diese Erweiterbarkeit durch eine Option für react-redux handhaben oder ein anderes Paket bereitstellen, das das Starterkit mit react-redux umhüllt

Ja, ich möchte nichts mit React-Redux für dieses erste MVP machen.

Gibt es in diesem Fall eine gute Möglichkeit, eine Abstraktion für Selektoren auf Redux-Ebene hinzuzufügen, oder können wir dies nur effektiv auf React-Redux-Ebene anwenden? Das Problem ist, dass wir nicht möchten, dass dies mit React-Redux inkompatibel ist. Wenn das nicht möglich ist, sollten wir die Selektoren vorerst aufgeben.

Solange es die Store-API implementiert, ist es mit React-Redux kompatibel. Wir wollen diese API nicht brechen, sondern nur DX verbessern.

Das macht Sinn. Ich habe keine Selektoren außerhalb von React-Redux verwendet, daher habe ich mich gefragt, ob sie für die Konfiguration von Redux selbst hier anwendbar sind.

@timdorr +1 auf den Wunsch, der mit einfacheren Reduzier-/Aktionspaaren ausgedrückt wird. Ich würde auch gerne eine Möglichkeit vorstellen, um die Erstellung eines Redux-Moduls (auch bekannt als das Entenmuster) zu vereinfachen, sodass das Erstellen eines Reduzierers, Aktionserstellers und Selektoren viel angenehmer und benutzerfreundlicher ist.

Ich denke, eine Lösung für dieses Problem zu finden, die die Mehrheit der Leute glücklich macht, erfordert etwas mehr Fahrradabwurf und ich frage mich, ob wir dies in einer Nachfolgeversion hinzufügen können, damit es keine Initialen blockiert Veröffentlichung.

Ich denke, was @markerikson in seinem Kommentar erstellt hat, reduziert bereits eine Menge Boilerplate und würde für eine großartige erste Vorabversion sorgen.

Danach können wir die anderen umständlichen Aspekte von Redux in Angriff nehmen (Erstellung von Redux/Aktionen/Selektoren).

Ich denke, der Versuch, alle Probleme im Voraus zu lösen, wird jede Form von greifbaren Fortschritten behindern.

Wenn Sie der Meinung sind, dass es fertig genug ist, denke ich, dass es eine gute Idee wäre, ein Repository zu starten, damit wir dieses Setup mit Beispielcode testen und ein bisschen dogfooden können (oder vielleicht ein Paket in einem Feature-Zweig des Monorepo, und wir könnten über PRs zusammenarbeiten).

Sicher. Mal sehen, ob ich heute etwas später etwas einrichten kann.

Wir brauchen kein weiteres Repository. Dies wird innerhalb des aktuellen existieren. Bitte machen Sie alles zuerst zu einer PR.

Sollte dies als separater Import Teil des Hauptpakets redux (also vollständig rückwärtskompatibel) oder bevorzugen Sie ein Monorepo mit mehreren Paketen? Ich denke, ersteres würde ausreichen, wir könnten immer einen anderen Dateiexport verwenden, ohne ein neues Paket zu erstellen, wenn es zu groß wird.

Ich würde damit gerne als separates Repo/Paket herumspielen, um damit zu beginnen, wirklich.

Es kann einfacher sein, das vorhandene Tooling-Setup in diesem Repository zu verwenden, da eine spätere Zusammenführung fehleranfällig sein könnte. Wir brauchen wahrscheinlich auch keine andere Syntaxunterstützung, da wir dieses React nicht spezifisch machen.

Wenn es sich um eine einzelne Datei mit einer Vorkonfiguration handelt, ist es am einfachsten, sie hier zu behalten. Aufgrund der Abhängigkeiten sollte es sich um ein separates Paket handeln. Damit wollen wir bestehende Apps nicht überfrachten.

Auch hier glaube ich nicht, dass wir auf Monorepo umsteigen müssen, aber wir können einen Ordner für bestimmte verpackte Builds haben, wenn wir mehr als einen erstellen. Nur ein starter Ordner mit seinem eigenen package.json sollte den Zweck erfüllen.

Ich mag die Idee, dies lokal im Hauptredux-Paket zu belassen, wenn es nur lokalen Code verwendet, um sich selbst zu reduxen. Ich werde zögerlicher, wenn wir anfangen, externe Abhängigkeiten einzubringen, um die hier geäußerten Ideen zu unterstützen.

Ich denke, einige externe Abhängigkeiten wie immer, thunk/promise/saga und reselect wären für unsere Ziele hier von unschätzbarem Wert und die zusätzlichen Abhängigkeiten für den Anfang wert, obwohl wir diese Abhängigkeiten möglicherweise nicht vom Hauptpaket redux selbst wollen .

Also, äh... Ich ging und tat etwas:

Dinge, die sich vom vorherigen Snippet unterscheiden:

  • Ich habe eine enhancers Konfigurationsoption eingefügt, nur weil
  • Ich habe die Abhängigkeit selectorator hinzugefügt und createSelector exportiert

Die Gedanken?

Als jemand, der sich Redux (und React) in den letzten Wochen selbst beigebracht hat, kann ich es kaum erwarten, das Endprodukt zu sehen. Ich bin mir sicher, dass ich eine Menge Zeug in meinem Code aufräumen muss.

😏 👍

Da es also lange darum geht, die Redux-Nutzung zu vereinfachen, könnte ich 2 Momente vorschlagen:

  1. Fügen Sie eine eingebaute Funktion zu expect(mapStateToProps(state)).toEqual(mapStateToProps(state)) . Nur um die Leute zu ermutigen, einen besseren Code zu erstellen. Ich habe noch nie solche Tests gesehen, aber _nicht-sehr-rein_ mapStateToProps ist eines von Redux-Problemen.

  2. Betrachten Sie eine Adoption als etwas wie memoize-state . Es ist wie Immer.js für Selektoren. Der entscheidende Punkt - der Kunde könnte einfach mapStateToProps oder selector in der von ihm bevorzugten Form schreiben und sich diese merken. Es könnte sogar dieses Neuauswahlproblem mit "Sharing Selectors with Props Across Multiple Component Instances" lösen, ohne dass die "gemeinsame" Memoisierung zwischen den Instanzen verloren geht. Merken Sie sich das Zeug einfach

  1. Ich verstehe, was Sie mit der Empfehlung reiner Selektoren meinen, aber ein unreiner idempotenter Selektor könnte diesen Test immer noch bestehen. Der zweite Vorschlag gefällt mir besser.
  2. Das klingt cool, also würden wir Selektoren genauso umwickeln wie Reduzierstücke zum Eintauchen, oder?

Wie wir oben besprochen haben, handelt es sich jedoch eher um eine React-Redux-Sache als um etwas, das im Starterpaket enthalten wäre, das React agnostisch ist.

Das ist wirklich cool!

Ich habe jedoch eine Bitte / ein bisschen Feedback; Mir wäre es lieber, wenn Immer nicht implizit verwendet würde.

Immer ist großartig . Es ist zu einem meiner Lieblings-Utilities geworden. Aber selbst wenn ich es explizit verwende ( produce(baseState, draftState => ... ), mache ich mir Sorgen, wenn andere Leute, die damit nicht vertraut sind, meinen Code sehen und nicht erkennen, dass ich diese mutativen Dinge nur aufgrund von Immer-Superkräften tun kann.

So wie die API jetzt aussieht, kann ich mir vorstellen, dass Neulinge nicht erkennen, dass der Redux-Zustand unveränderlich sein sollte. Ich denke, dass Missverständnisse sie hart treffen würden, wenn sie versuchen, Redux ohne dieses Starter-Kit zu verwenden.

Ich sehe, dass createNextState bereits ein Export ist. Warum also nicht die Benutzer ermutigen, ihn explizit zu verwenden:

import {createReducer, createNextState} from "@acemarke/redux-starter-kit";

function addTodo(state, newTodo) {
    return createNextState(state, draftState => {
        draftState.push({...newTodo, completed : false});
    });
}

(Entschuldigung, wenn ich falsch verstanden habe, wie createNextState verwendet werden soll! Habe mich überhaupt nicht damit beschäftigt)

Siehe https://github.com/markerikson/redux-starter-kit/issues/5.

So wie die API jetzt aussieht, kann ich mir vorstellen, dass Neulinge nicht erkennen, dass der Redux-Zustand unveränderlich sein sollte. Ich denke, dass Missverständnisse sie hart treffen würden, wenn sie versuchen, Redux ohne dieses Starter-Kit zu verwenden.

Meiner Meinung nach sollten wir aufgrund von https://github.com/reactjs/redux/issues/2858 davon abraten, Redux direkt zugunsten dieses Pakets zu verwenden, wenn es vollständig ist

Ich sehe, dass createNextState bereits ein Export ist, also warum nicht die Benutzer ermutigen, es explizit zu verwenden:

Keine schlechte Idee, aber ich denke, wir sind hier eher dafür, implizit zu sein, insbesondere weil wir keinen Quellcode generieren und das Hinzufügen von immer rückkompatibel ist.

Ich sehe viele Leute, die empfehlen, libs wie immer.js , was meiner bescheidenen Meinung nach darin besteht, die Motivation des Lernens und die Einhaltung der store Anforderungen unwissentlich abzulenken.

Wir alle wissen, dass der Store nicht mutiert werden kann, daher hätte ich lieber einen Validierungsmechanismus, bei dem die newState Instanz gegen ( === ) die previousState geprüft wird und wenn es sich um dieselbe Instanz handelt, wird ein Fehler ausgelöst.

Auf diese Weise würde jeder gezwungen sein, die Regeln und Anforderungen von store zu lernen.

PS: Ich verstehe wirklich den Vorteil von immer und ich habe absolut nichts dagegen, aber wir erreichen einen Zeitpunkt, an dem die Leute das Konzept endlich verstehen. Wenn wir es vergleichen, würden wir nichts anderes tun, als eine zusätzliche Ebene an Komplexität hinzuzufügen, nur um die Bibliothek aufzulockern.

Persönliche Vorschläge:

Die logger , devTools und Thunk sollten als Standard der Starter hinzugefügt werden, der Rest ist meiner Meinung nach eher eine persönliche Wahl.

Wir alle wissen, dass der Speicher nicht mutiert werden kann, daher hätte ich lieber einen Validierungsmechanismus, bei dem die newState-Instanz mit ( === ) dem previousState verglichen wird und wenn es sich um dieselbe Instanz handelt, wird ein Fehler ausgegeben.

Es gibt Fälle, in denen Sie je nach Aktion nicht möchten, dass sich der Status ändert, sodass Sie dieselbe Speicherinstanz zurückgeben, um Speicher zu sparen und falsch positive Differenzen zu vermeiden. Selbst wenn wir dieses Problem umgangen haben, scheint Redux keinen Validator im Kern zu haben, und ich denke, Immer ist ein persönlicher Schutz dafür. Ich stimme zu, dass es den Zweck des Erlernens von Redux in gewisser Weise zunichte macht, aber ich sehe so viele Entwickler, die Redux lernen, die nicht reines FP lernen wollen oder sich dessen nicht bewusst sind.

Wenn wir es vergleichen, würden wir nichts anderes tun, als eine zusätzliche Ebene an Komplexität hinzuzufügen, nur um die Bibliothek aufzulockern.

Soweit mir bekannt ist, hat die Art und Weise, wie Immer der Proxy implementiert ist, nur dann einen Performance-Overhead, wenn er tatsächlich mutiert ist, sodass typische unveränderliche Update-Reduzierer keinen Performance-Overhead haben sollten. Ich denke, das ist eine ok Balance.

Der Logger, devTools und Thunk sollten als Standard zum Starter hinzugefügt werden, der Rest ist meiner Meinung nach eher eine persönliche Wahl.

Es gibt noch einige andere Dinge, die ich gerne entfernen würde (obwohl ich persönlich keinen großen Vorteil für den Logger gegenüber den Entwicklertools sehe, der den Performance-Overhead ausgleicht), siehe https://github.com/markerikson/ redux-starter-kit/issues/19. Ich bin jedoch nicht dagegen, weitere Dinge hinzuzufügen, wenn sie wieder kompatibel sind, wie unsere aktuelle Verwendung von Immer und Thunk.

Es gibt Fälle, in denen Sie je nach Aktion nicht möchten, dass sich der Status ändert, sodass Sie dieselbe Speicherinstanz zurückgeben, um Speicher zu sparen und falsch positive Differenzen zu vermeiden. Selbst wenn wir dieses Problem umgangen haben, scheint Redux keinen Validator im Kern zu haben, und ich denke, Immer ist ein persönlicher Schutz dafür. Ich stimme zu, dass es den Zweck des Erlernens von Redux in gewisser Weise zunichte macht, aber ich sehe so viele Entwickler, die Redux lernen, die nicht reines FP lernen wollen oder sich dessen nicht bewusst sind.

@nickmccurdy Ich verstehe Ihren Standpunkt vollkommen und stimme zu, dass wir aufgrund einiger Konzepte von FP, Mutation usw. keine Lernhindernisse haben sollten ... Aber als Pädagoge glaube ich fest daran, den Lehrling nicht zu beschönigen die Komplexität vor ihnen verbergen. Wie auch immer, es ist nur eine Frage des Geschmacks, ich bin ein Lernprofi und Vorwärtsdrang, und wenn ich mir diesen Vorschlag ansehe, sagt mir mein Instinkt irgendwie, dass wir mit Akzeptanz vorankommen würden, aber mit Standards zurückgehen würden. Denken Sie nur an alle Inhalte im Web, die gerade Redux Standards lehren, und wie es endlich ankommt.

Soweit mir bekannt ist, hat die Art und Weise, wie Immer der Proxy implementiert ist, nur dann einen Performance-Overhead, wenn er tatsächlich mutiert ist, sodass typische unveränderliche Update-Reduzierer keinen Performance-Overhead haben sollten. Ich denke, das ist eine ok Balance.

Wenn ich eine Komplexitätsebene hinzufügen möchte, meine ich, dass Immer noch nie da war und jetzt könnte es möglicherweise sein, wir müssten es in der Bibliothek unterstützen, testen, Leistungsprobleme bewerten und nicht zuletzt Dieser Abschnitt hier macht mich besorgt:

Immer.js -
Immer friert automatisch alle Zustandsbäume ein, die mithilfe von "produzieren" geändert wurden. Dies schützt vor versehentlichen Änderungen des Zustandsbaums außerhalb eines Produzenten. Dies hat Auswirkungen auf die Leistung, daher wird empfohlen, diese Option in der Produktion zu deaktivieren. Es ist standardmäßig aktiviert. Standardmäßig ist es während der lokalen Entwicklung aktiviert und in der Produktion deaktiviert. Verwenden Sie setAutoFreeze(true / false), um diese Funktion explizit ein- oder auszuschalten.

Und plötzlich müssen wir auch Funktionen unterstützen, die in Development / Prod hinzugefügt wurden. Es ist nur eine Menge Arbeit und besorgniserregend, da nicht viel abgegolten werden muss, aber auch dies ist nur meine persönliche Meinung.

@codedavinci : Der Sinn dieser redux-starter-kit Bibliothek besteht darin, nützliche Tools und Abstraktionen zusätzlich zum "grundlegenden" Redux-Store-Setup-Prozess hinzuzufügen. Beachten Sie auch, dass dies _nicht_ in den Redux-Kern selbst geht, sondern eher in eine separate Bibliothek, die wir irgendwann zu einem "offiziellen" Teil der Redux-Organisation machen möchten.

Ihr gesamter vorhandener Redux-Code wird funktionieren. Alle bestehenden Tutorials werden weiterhin in Ordnung sein. Wir versuchen nur, einen offiziell unterstützten einfacheren Ansatz zum Einrichten und Verwenden von Redux hinzuzufügen.

@markerikson Ich verstehe das Ziel des Starter-Kits und bin voll und ganz unten für alles, was oben erwähnt wurde, nur ein bisschen resistent gegen eine Bibliothek wie Immer.js , die das Konzept der Bibliothek ändert, werden die Leute irgendwann lernen starter-kit Muster und ignorieren Sie die Kernkonzepte vollständig. Keine Store-Mutation ist das Motto, Redux hat es immer verkauft, es ist Teil der Marke.

PS: Ich verstehe voll und ganz, dass Immer.js nichts mutiert, sondern dir hilft, es nicht zu tun, ich spreche nur und nur von syntaktisch erlaubten Standards wie push , splice ...

Vielleicht bin ich nur resistent gegen Veränderungen :)

@codedavinci : Ja, ich verstehe den Sinn der Bedenken. Eine der häufigsten Beschwerden über Redux ist jedoch, dass es schwierig ist, richtigen unveränderlichen Update-Code zu schreiben, und Immer ist einfach die beste Bibliothek, die ich zur Vereinfachung dieser Updates gesehen habe.

@markerikson , ich habe mich tatsächlich mit dem immer und festgestellt, dass es sehr leicht, einfach und effizient ist. Ich bin tatsächlich verkauft :) .

Welches Repo entwirfst du? jene:

https://github.com/markerikson/redux-starter-kit
https://www.npmjs.com/package/@acemarke/redux-starter-kit
https://unpkg.com/@acemarke/redux [email protected]/

Ja, das ist es.

@nickmccurdy hat eine Reihe von PRs, die auf Diskussion und Fusion warten, hauptsächlich um Tools, aber auch einige Diskussionen darüber, wie wir das Projekt längerfristig

Toller Fortschritt @nickmccurdy & @markerikson 👍 Ich liebe die Einfachheit und Effektivität davon. @nickmccurdy hat bemerkt, dass Sie sehr aktiv an dem Projekt beteiligt sind. Ich würde gerne mit Ihnen über einige Ideen

Klar danke, es ist wahrscheinlich am besten, eine offene Diskussion in einer neuen Ausgabe zu starten, aber du kannst mich direkt über [email protected] oder auf Discord erreichen.

+1 für das Aufteilen von combineReducers . Ich habe es die längste Zeit benutzt und weil ich nicht wirklich darüber nachgedacht habe, wie mein Laden funktioniert.

Derzeit richte ich meine Reduzierfunktion gerne wie folgt ein:

function reducer(prevState, event, handledNavigation = false) {
  if (event.type === 'NAVIGATION' && !handledNavigation) {
    return reducer(onNavigate(prevState, event), event, true);
  }

  const pageReducer = pageReducers[prevState.activePage];

  const nextSessionState = sessionReducer(prevState.sessionState, event);
  const nextPageState = pageReducer(prevState.pageState, nextSessionState, event);

  return {
    activePage: prevState.activePage,
    pageState: nextPageState,
    sessionState: nextSessionState,
  };
}

Was mir CombineReducers nicht wirklich erlaubt.

@abradley2 : Wir planen nicht, combineReducers aus dem Redux-Kern zu entfernen, wenn Sie das wünschen. Aber ja, wir haben immer gesagt, dass combineReducers ein Dienstprogramm für den häufigsten Anwendungsfall ist und dass Sie ermutigt werden, benutzerdefinierte Reduzierlogik für Ihre eigene Situation zu schreiben.

Wir haben den Paketnamen redux-starter-kit und das Repository wurde in die Organisation unter https://github.com/reduxjs/redux-starter-kit verschoben. Werde diesen Thread schließen. Jede weitere Diskussion kann in diesem Repo stattfinden.

Außerdem fange ich an, standardmäßig Mutations- und Serialisierbarkeitsprüfungen hinzuzufügen.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

jbri7357 picture jbri7357  ·  3Kommentare

mickeyreiss-visor picture mickeyreiss-visor  ·  3Kommentare

amorphius picture amorphius  ·  3Kommentare

caojinli picture caojinli  ·  3Kommentare

CellOcean picture CellOcean  ·  3Kommentare