Redux: RFC : Kit de démarrage Redux

Créé le 1 mars 2018  ·  56Commentaires  ·  Source: reduxjs/redux

D'après les commentaires du #2858 et des précédents #2295, cela ressemble à un kit de démarrage préconfiguré du noyau Redux + quelques middleware communs + des amplificateurs de magasin + d'autres outils pourraient être utiles pour démarrer avec la bibliothèque.

J'ai commencé par réserver un nom de package (je n'y suis pas pour rien, cependant) et nous pouvons commencer à remplir les blancs là-bas. J'aimerais conserver le contenu de ce paquet ici, afin que nous n'ayons pas à configurer un autre dépôt ou quoi que ce soit. Nous voudrons peut-être enquêter sur un monorepo, mais je ne pense pas qu'il y ait un besoin pressant actuellement.

Une chose que j'aimerais étudier en même temps : diviser combineReducers en son propre package. C'est la seule chose qui devient normative sur la façon de structurer et d'exploiter un magasin. Ce n'est évidemment pas le seul moyen, mais je crains que beaucoup de gens ne voient pas au-delà.

En ce qui concerne ce qui se passe dans un package de démarrage, la courte liste dans mon esprit comprend l'une des bibliothèques de réduction standard (ou quelque chose que nous construisons), un middleware populaire comme les thunks et les sagas, et des outils de développement utiles. Nous pourrions avoir un package de sous-ensemble pour les utilisateurs spécifiques à React. En fait, j'ai lancé un sondage Twitter pour savoir si c'est même nécessaire (s'il vous plaît RT !).

Je ne pense pas que nous ayons besoin de créer une expérience de type Create React App avec un outil CLI et tout ce jazz. Mais quelque chose hors de la boîte qui donne une excellente expérience de développement avec un meilleur débogage et moins de code.

discussion ecosystem feedback wanted

Commentaire le plus utile

Alors, euh... je suis allé et j'ai fait une chose :

Choses qui sont différentes de l'extrait précédent :

  • J'ai ajouté une option de configuration enhancers , juste parce que
  • J'ai ajouté la dépendance selectorator et exporté createSelector

Les pensées?

Tous les 56 commentaires

OUI OUI OUI! J'AI BEAUCOUP D'OPINIONS ET DE SOUHAITS POUR CELA ! Mais je vais me retenir et laisser la discussion commencer en premier.

Un élément de liste de souhaits dont je ne suis pas sûr qu'il soit réalisable est le HMR intégré pour les réducteurs automatiquement ajouté dans une fonction createReduxStore() . Malheureusement, ma connaissance de Webpack et certaines expérimentations indiquent que ce n'est pas très faisable, car vous devez avoir des chemins codés en dur vers les fichiers de réduction dans les rappels Webpack module.hot.accept() . Je ne sais pas comment Parcel ou d'autres bundlers gèrent cela.

Donc, première demande de retour de chacun :

  • Quelles sont les principales exigences que nous voudrions satisfaire avec ce package ?
  • Quels packages _existants_ suggéreriez-vous pour répondre à ces exigences ?
  • Comment pouvons-nous combiner au mieux ces packages pour simplifier les choses pour l'utilisateur final ?

Nommons 3 points clés, où les variantes possibles seront _isolées_ les unes des autres.

  1. Premier point. Gestionnaires de réducteurs
    1.0 Vanille (c'est le cas ici ?)
    1.1 Immer.js
    1.2 Corédux
    1.3 100500 paquets supplémentaires

  2. Deuxième point. Middlewares
    2.0 Vanille (est-ce le cas ?)
    2.1 Les sagas
    2.2 Épiques
    2.3 100500 paquets supplémentaires.

  3. Troisième point. Intégration React
    3.0. Vanille (c'est le cas ici ?)
    3.1. Sous-espace
    3.2 Reformuler
    3.3 100500 paquets supplémentaires.

4ème, bonus, point
4.0 Tester tout cela dans un _boilerplate_.

Il est impossible de choisir "les élus", par exemple j'aime et utilise à la fois les Sagas et les Epics, mais possible de fournir des "recettes de cuisine" et des recommandations de combinaisons .

Par exemple, la plupart des utilisateurs de redux connaissent __seulement__ les middlewares. Une petite partie fait également quelque chose avec des réducteurs (d'accord beaucoup _entendu_ à propos d'immutable.js), quelques-uns améliorent l'intégration de React.

Le kit de démarrage pourrait simplement aider à créer une approche complète et _riche_ dès le début. Ou il en faut plus qu'un seul kit de démarrage.

Demandé des commentaires sur les points douloureux de la configuration/du standard sur Twitter : https://twitter.com/acemarke/status/969040835508604929

Copie de ma réponse sur twitter :

Je suis explicitement resté à l'écart de l'ajout de redux passe-partout car l'OMI ajoute de la complexité lors de l'introduction de «votre façon» de faire la redux à une autre personne. J'aimerais davantage de conventions normatives appliquées via le code pour faire du redux une compétence plus portable.

À cette fin, avoir un référentiel create-redux-app style

Nous en avons un peu parlé sur Reactiflux, nous voulions copier une consolidation des désirs d'inclusion dans ce fil, une partie de cela chevauche les points que vous avez déjà énumérés @timdorr (c'est donc une confirmation enthousiaste).

  1. wrapper autour de createStore avec de meilleures valeurs par défaut, c'est-à-dire un moyen plus facile d'ajouter des middleware, des outils de développement redux
  2. assistant immuable intégré (immer?)
  3. createReducer intégré (l'utilitaire standard de "table de recherche de réducteur")
  4. resélectionner
  5. créateur d'action qui adhère à la FSA
  6. prise en charge de l'action async / prise en charge des effets secondaires (flux, saga, quoi ?)

Pourquoi ne pas soutenir officiellement quelque chose qui existe déjà, comme le redux-bundler d'Henrik Joreteg ?

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

Il est concis, avisé (dans le bon sens), permet la réutilisation des fonctionnalités liées au redux dans les applications et offre toujours une bonne solution pour la gestion asynchrone.

C'est un projet fascinant, et un que je veux vraiment approfondir, mais il est également hors de portée pour ce que je veux faire avec cette tâche.

Ce que je veux vraiment accomplir ici, c'est :

  • Configuration d'un magasin Redux avec quelques lignes de code et des choix de configuration minimaux nécessaires (l'équivalent Redux du slogan "zero-config JS" utilisé par Webpack et Parcel).
  • Semblable à CRA, les éléments de configuration sont fondamentalement cachés, avec de bonnes valeurs par défaut prêtes à l'emploi
  • Inclusion de packages soigneusement sélectionnés pour améliorer l'expérience de développement et, oui, "réduire le passe-partout". Par exemple, Immer serait un excellent choix car il simplifie considérablement l'écriture d'une logique de réduction immuable _et_ gèle votre état dans dev. (Ma seule hésitation est que l'apparition d'un code qui "mute" serait déroutant.)

Je veux garder cet effort assez étroitement limité. J'ai discuté avec @hswolff et @nickmccurdy dans Reactiflux ces dernières heures, et bien que la discussion ait été excellente, nous avons déjà parcouru une douzaine de cas d'utilisation et d'idées qui se chevauchent et qui pourraient vraiment compliquer les choses.

Je veux rassembler _quelque chose_ d'utile, de valeur et de viable sans trop de pertes de vélos, puis avoir d'autres discussions en marge (comme une API pour créer des "bundles" ou des "modules" Redux), etc.).

Pour donner le coup d'envoi à une première utilisation des API, voici une idée de base pour 1 à 3 de ma liste que j'ai publiée ci-dessus :

// #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() {}

Ouais, je creuse ça. Je m'attendrais alors à ce qu'il ajoute toujours thunk() au début de la liste des middlewares, ou peut-être seulement si vous n'avez fourni aucun middleware vous-même. Nous pourrions même ne pas vouloir autoriser l'utilisateur à spécifier des amplificateurs ici. Nous ajouterions applyMiddleware() automatiquement s'il y avait un middleware, et utiliserions la fonction composeWithDevtools de redux-devtools-extension if devTools : true . Pour les besoins de cette "configuration facile", je pense que nous pouvons vouloir éliminer les "amplificateurs" des choses que l'utilisateur peut configurer.

+1 sur l'élimination des amplificateurs.

Sur votre point de thunk étant automatiquement ajouté, nous devrions pouvoir avoir notre gâteau et le manger aussi via l'exportation de la fonction que nous utiliserions pour ajouter un middleware par défaut :

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)
})

Oui, c'est à peu près ce que je pensais. Ma principale préoccupation est de savoir si l'utilisateur essaie accidentellement de fournir sa propre instance de thunk .

J'ai décidé de jouer un peu avec les choses ce soir. Voici une première coupe. Les pensées?

// 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};

Et l'exemple obligatoire d'application todo :

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());

Je pense que c'est un bon début et un bon début pour la bibliothèque discutée dans ce fil. Il couvre les points 1, 2, 3 et 6 de ma liste de fonctionnalités souhaitées ci-dessus.

Itérer au-dessus de cela serait formidable, mais c'est une base solide.

Plutôt que de nous concentrer sur la mise en œuvre, j'aimerais que nous nous concentrions sur le DX. Que sont les exports/API et comment sont-ils utilisés ? Je pense que c'est une excellente occasion de dépasser uniquement la configuration et de voir comment les gens utilisent le magasin. Quelques idées aléatoires :

Paires réducteur/action plus faciles :

Facilitez l'association de vos réducteurs et actions avec leur sortie d'état. C'est approximatif, mais voici l'idée de base :

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!'))

Magasin Singleton

Celui-ci, je ne suis pas du tout convaincu, mais je repensais à l'époque où nous avions des singletons d'histoire dans React Router. Ce n'était pas parfait, mais cela offrait une certaine valeur.

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

configureStore(reducer, middleware, initialState)

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

Configurabilité via import

Je garde mes plus loufoques pour la fin. Mais que se passerait-il si nous autorisions la configuration en important des fichiers. Nous aurions besoin de quelques passes globales dans les coulisses, ce qui devient désordonné/gênant. Mais encore une fois, l'accent est mis sur l'utilisateur, pas sur notre côté.

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'

Pour ce deuxième exemple, je peux voir des utilisateurs créer des alias vers ce package dans leurs outils de construction ou faire quelque chose comme ce que fait React .

OK, c'est tout pour moi pour le moment. Encore une fois, je veux penser à l'utilisateur d'abord. Quels que soient les hacks sales et laids que nous devons faire pour mettre en œuvre cela, cela n'a pas d'importance. L'essentiel est un excellent DX avec moins de code écrit et moins de configuration nécessaire.

J'adore ces idées jusqu'à présent. Mon seul souhait pour tout ce que cela pourrait être serait un accès gracieux à l'API Redux standard de niveau inférieur. Il doit y avoir un chemin naturel pour que les gens puissent personnaliser ou éjecter. Que ce soit dans quelques jours, un an ou deux, cela devrait être simple. Le verrouillage est l'un des problèmes que je vois (de ma propre tentative avec Jumpstate et de bibliothèques plus récentes comme Rematch). Plus nous pouvons éviter cela, meilleur sera le goût des gens dans la bouche :)

Oui, j'ai vu pas mal de bibliothèques utilitaires qui font des trucs comme ce "pack d'action" (au moins en ce qui concerne l'aspect "écrire des réducteurs, transformer les clés en types d'action et en créateurs d'action"), et j'envisageais de lancer cela en tant qu'élément supplémentaire - n'y était tout simplement pas encore arrivé. Pas sûr de l'aspect "combineActionPack".

J'ai eu une discussion supplémentaire avec @hswolff hier soir. J'aimerais envisager d'ajouter/réexporter la bibliothèque de sélecteurs , qui semble être un sur-ensemble de l'API Reselect avec quelques avantages utiles supplémentaires :

import createSelector from 'selectorator';

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

Cela aiderait à réduire de nombreux sélecteurs de "simple entrée" écrits à la main, comme const selectTodos = state => state.todos .

Je ne suis pas sûr de voir l'avantage d'ajouter une bibliothèque de sélecteurs. Nous devrions également fournir une opinion sur la forme de l'État qu'elle permet.

C'est au moins en partie juste pour qu'il y ait un élément de moins que l'utilisateur doit installer dans package.json .

Je pense qu'une bibliothèque de sélection serait géniale.

Également pertinent : l'article récent sur le kit de démarrage apollo-boost

Si nous pouvons étendre l'API de react-redux de connect pour utiliser reselect (ou une bibliothèque de sélecteur similaire) lorsque le mapStateToProps est un Array , nous pourrions encourager l'utilisation de sélecteurs et le rendre très pratique sans rompre la compatibilité. Je ne pense pas que cette bibliothèque devrait nécessairement être couplée avec React ou react-redux , mais peut-être pourrions-nous gérer cette extensibilité via une option pour react-redux ou fournir un autre package enveloppant le kit de démarrage avec react-redux soutien.

Oui, je ne cherche pas à faire quoi que ce soit avec React-Redux pour ce premier MVP.

Dans ce cas, existe-t-il un bon moyen d'ajouter une abstraction pour les sélecteurs au niveau Redux ou est-ce quelque chose que nous ne pourrions faire efficacement qu'en plus de react-redux ? Le problème est que nous ne voudrions pas que cela soit incompatible avec react-redux, donc je suppose que si ce n'est pas possible, nous devrions abandonner les sélecteurs pour le moment.

Tant qu'il implémente l'API du magasin, il est compatible avec react-redux. Nous ne cherchons pas à casser cette API, mais simplement à améliorer DX.

Ça a du sens. Je n'ai pas utilisé de sélecteurs en dehors de react-redux, donc je me demandais s'ils seraient applicables à la configuration de Redux lui-même ici.

@timdorr +1 sur le désir exprimé avec des couples réducteur/action plus faciles. J'aimerais également présenter un moyen de faciliter la création d'un module de redux (alias le modèle de canards) de sorte que la création d'un réducteur, de créateurs d'action et de sélecteurs soit une expérience beaucoup plus agréable et plus facile à utiliser.

Je pense que trouver une solution à ce problème qui rend la majorité des gens heureux nécessitera un peu plus de délestage de vélo et je me demande si c'est quelque chose que nous pouvons ajouter dans une version de suivi afin qu'il ne bloque pas un premier Libération.

Je pense que ce que @markerikson a créé dans son commentaire réduit déjà beaucoup de passe-partout et constituerait une excellente pré-version initiale.

Après cela, nous pouvons aborder les autres aspects de Redux qui sont encombrants (création redux/action/selector).

Je pense qu'essayer de résoudre tous les problèmes à l'avance va entraver toute forme de progrès tangible.

Si vous pensez que c'est assez prêt, je pense que ce serait une bonne idée de démarrer un référentiel afin que nous puissions tester cette configuration avec un exemple de code et un peu de dogfood (ou peut-être un package dans une branche de fonctionnalité du monorepo, et nous pourrions collaborer par le biais des PR).

Sûr. Je vais voir si je peux mettre quelque chose en place un peu plus tard aujourd'hui.

Nous n'avons pas besoin d'un autre référentiel. Celui-ci existera dans l'actuel. S'il vous plaît faire n'importe quoi un PR d'abord.

Cela devrait-il faire partie du package principal redux en tant qu'importation distincte (donc c'est complètement rétrocompatible) ou préférez-vous un monorepo avec plusieurs packages ? Je pense que le premier serait suffisant, nous pourrions toujours utiliser un autre fichier d'exportation sans créer de nouveau package s'il devient trop gros.

J'aimerais un peu jouer avec cela en tant que repo/package séparé pour commencer, vraiment.

Il peut être plus facile d'utiliser la configuration d'outillage existante dans ce référentiel, car sa fusion future pourrait être sujette à des erreurs. Nous n'avons probablement pas non plus besoin d'un support de syntaxe différent car nous ne rendons pas ce React spécifique.

S'il s'agit d'un seul fichier avec une pré-configuration, il serait plus facile de le conserver ici. En raison des dépendances, il devrait s'agir d'un package distinct. Nous ne voulons pas encombrer les applications existantes.

Encore une fois, je ne pense pas que nous ayons besoin d'aller en monorepo, mais nous pouvons avoir un dossier pour des builds packagés spécifiques si nous commençons à en créer plusieurs. Juste un dossier starter pour l'instant avec son propre package.json devrait faire l'affaire.

J'aime l'idée de garder cela local dans le package de redux principal s'il n'utilise que du code local pour se redoxer. Je deviens plus hésitant si nous commençons à tirer des dépendances externes pour soutenir les idées exprimées ici.

Je pense que certaines dépendances externes telles que immer, thunk/promise/saga et reselect seraient inestimables pour nos objectifs ici et vaudraient les dépendances supplémentaires pour le démarreur, bien que nous ne voudrions peut-être pas ces dépendances sur le package principal redux lui-même .

Alors, euh... je suis allé et j'ai fait une chose :

Choses qui sont différentes de l'extrait précédent :

  • J'ai ajouté une option de configuration enhancers , juste parce que
  • J'ai ajouté la dépendance selectorator et exporté createSelector

Les pensées?

En tant que personne qui vient d'apprendre tout seul Redux (et React) au cours des deux dernières semaines, j'ai hâte de voir le produit final. Je suis sûr que je vais avoir une tonne de choses à nettoyer dans mon code.

👍

Donc, comme l'idée longue est de simplifier l'utilisation du redux, je pourrais proposer 2 moments :

  1. Ajoutez une fonction intégrée à littéralement expect(mapStateToProps(state)).toEqual(mapStateToProps(state)) . Juste pour encourager les gens à créer un meilleur code. Je n'ai jamais vu de tests comme celui-ci, mais _pas-très-pur_ mapStateToProps est l'un des problèmes de redux.

  2. Considérez l'adoption quelque chose comme memoize-state . C'est comme Immer.js pour les sélecteurs. Le point clé - le client peut simplement écrire mapStateToProps ou selector sous la forme qu'il préfère, et le mémoriser. Cela pourrait même résoudre ce problème de resélection avec "Partage de sélecteurs avec des accessoires sur plusieurs instances de composants" sans perdre la mémorisation "commune" entre les instances. Juste double mémoriser le truc

  1. Je vois ce que vous voulez dire en termes de recommandation de sélecteurs purs, mais un sélecteur idempotent impur pourrait toujours réussir ce test. J'aime plus la deuxième suggestion.
  2. Ça a l'air cool, donc nous envelopperions simplement les sélecteurs de la même manière que nous envelopperions les réducteurs pour l'immersion, n'est-ce pas ?

Pourtant, comme nous en avons discuté ci-dessus, il s'agit plus d'une chose de re-redux que de quelque chose qui serait dans le package de démarrage qui est agnostique de React.

C'est vraiment cool!

J'ai cependant une demande/un retour d'information ; Je préférerais qu'Immer ne soit pas utilisé implicitement.

Immer est super . C'est devenu l'un de mes utilitaires préférés. Mais même en l'utilisant explicitement ( produce(baseState, draftState => ... ), je m'inquiète du fait que d'autres personnes qui ne le connaissent pas voient mon code et ne réalisent pas que je ne peux faire ces choses mutatives qu'à cause des super pouvoirs Immer.

Vu l'apparence actuelle de l'API, je peux imaginer que les nouveaux arrivants ne réalisent pas que l'état de redux devrait être immuable. Je pense que ce malentendu les mordrait fort lorsqu'ils essaieraient d'utiliser Redux sans ce kit de démarrage.

Je vois que createNextState est déjà une exportation, alors pourquoi ne pas encourager les utilisateurs à l'utiliser explicitement :

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

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

(excuses si j'ai mal compris comment createNextState est destiné à être utilisé ! Je n'y ai pas du tout creusé)

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

Vu l'apparence actuelle de l'API, je peux imaginer que les nouveaux arrivants ne réalisent pas que l'état de redux devrait être immuable. Je pense que ce malentendu les mordrait fort lorsqu'ils essaieraient d'utiliser Redux sans ce kit de démarrage.

À mon avis, nous devrions déconseiller d'utiliser Redux directement en faveur de ce package lorsqu'il est terminé à cause de https://github.com/reactjs/redux/issues/2858. Fondamentalement, nous voulons avertir ou protéger les utilisateurs de toutes les mutations par défaut, mais nous ne pouvons pas le faire facilement dans le noyau sans casser les choses, nous devrions donc vous déconseiller d'utiliser le noyau, sauf dans les cas extrêmes où le kit de démarrage n'est pas suffisant. Ceci est similaire à la façon dont React recommande CRA et Redux recommande react-redux lors de l'utilisation de React.

Je vois que createNextState est déjà une exportation, alors pourquoi ne pas encourager les utilisateurs à l'utiliser explicitement :

Ce n'est pas une mauvaise idée, mais je pense que nous sommes plus en faveur d'être implicite ici surtout parce que nous ne générons pas de code source et que l'ajout d'immer est de retour compatible.

Je vois beaucoup de gens recommander d'utiliser libs comme immer.js , ce qui à mon humble avis consiste à dévier involontairement de la motivation d'apprendre et de respecter les exigences de store .

Nous savons tous que le magasin ne peut pas être muté, donc, je préférerais de loin avoir un mécanisme de validation où il vérifie l'instance newState contre ( === ) le previousState et s'il s'agit de la même instance, lancez une erreur.

De cette façon, tout le monde serait obligé d'apprendre les règles et les exigences du store .

PS : Je comprends vraiment l'avantage de immer et je n'ai absolument rien contre, mais nous arrivons à un moment où les gens comprennent enfin le concept, cela générerait une énorme source de confusion, et techniquement, ils diraient : si nous le comparions, nous ne ferions rien d'autre que d'ajouter une couche supplémentaire de complexité juste pour assouplir la bibliothèque.

Suggestions personnelles :

Les logger , devTools et Thunk devraient être ajoutés par défaut aux Starter , le reste je pense est plus un choix personnel.

Nous savons tous que le magasin ne peut pas être muté, donc, je préférerais de loin avoir un mécanisme de validation où il vérifie l'instance newState par rapport ( === ) à l'état précédent et si c'est la même instance, jette une erreur.

Il existe des cas où, en fonction de l'action, vous ne voudriez pas que l'état change, vous renverriez donc la même instance de magasin pour économiser de la mémoire et éviter toute différence faussement positive. Même si nous avons contourné ce problème, il semble que Redux ne veuille pas de validateur dans le noyau et je pense que Immer est une bonne protection pour cela personnellement. Je suis d'accord pour dire que cela va à l'encontre de l'objectif d'apprendre Redux dans une certaine mesure, mais je vois tellement de développeurs apprendre Redux qui ne veulent pas apprendre la FP pure ou qui n'en sont pas conscients.

si nous le comparions, nous ne ferions rien d'autre que d'ajouter une couche supplémentaire de complexité juste pour assouplir la bibliothèque.

Pour autant que je sache, la façon dont Immer est implémenté, le proxy n'a de surcharge de performances que s'il est réellement muté, de sorte que les réducteurs de mise à jour immuables typiques ne devraient pas avoir de surcharge de performances. Je pense que c'est un bon équilibre.

Le logger, devTools et Thunk devraient être ajoutés par défaut au Starter, le reste, je crois, est plus un choix personnel.

Il y a d'autres choses que j'aimerais envisager de supprimer (bien que personnellement, je ne vois pas un énorme avantage pour l'enregistreur par rapport aux outils de développement qui compensent sa surcharge de performances), voir https://github.com/markerikson/ redux-starter-kit/issues/19. Cependant, je ne suis pas contre l'ajout d'autres éléments s'ils sont de nouveau compatibles, comme notre utilisation actuelle d'Immer et de Thunk.

Il existe des cas où, en fonction de l'action, vous ne voudriez pas que l'état change, vous renverriez donc la même instance de magasin pour économiser de la mémoire et éviter toute différence faussement positive. Même si nous avons contourné ce problème, il semble que Redux ne veuille pas de validateur dans le noyau et je pense que Immer est une bonne protection pour cela personnellement. Je suis d'accord pour dire que cela va à l'encontre de l'objectif d'apprendre Redux dans une certaine mesure, mais je vois tellement de développeurs apprendre Redux qui ne veulent pas apprendre la FP pure ou qui n'en sont pas conscients.

@nickmccurdy Je comprends parfaitement votre point de vue, et je suis d'accord pour dire que nous ne devrions pas avoir d'obstacle à l'apprentissage en raison de certains concepts de PF, de mutation, etc. leur cacher la complexité. Quoi qu'il en soit, c'est juste une question de goût, je suis un pro de l'apprentissage et de l'anticipation, et en regardant cette proposition, mon instinct me dit en quelque sorte que nous avancerions avec l'acceptation, mais régresserions avec les normes. Juste à noter, pensez à tout le contenu sur le Web qui enseigne actuellement les normes Redux et à la façon dont il est finalement adopté.

Pour autant que je sache, la façon dont Immer est implémenté, le proxy n'a de surcharge de performances que s'il est réellement muté, de sorte que les réducteurs de mise à jour immuables typiques ne devraient pas avoir de surcharge de performances. Je pense que c'est un bon équilibre.

Quand je veux dire ajouter une couche de complexité, je veux dire que Immer n'a jamais été là et maintenant cela pourrait éventuellement l'être, nous devrons le prendre en charge dans la bibliothèque, tester, évaluer les problèmes de performances et enfin et surtout cette section ici, me fait peur:

Immer.js - Congélation automatique
Immer gèle automatiquement tous les arbres d'état qui sont modifiés à l'aide de produire. Cela protège contre les modifications accidentelles de l'arbre d'état en dehors d'un producteur. Cela a un impact sur les performances, il est donc recommandé de désactiver cette option en production. Il est activé par défaut. Par défaut, il est activé lors du développement local et désactivé en production. Utilisez setAutoFreeze(true / false) pour activer ou désactiver explicitement cette fonctionnalité.

Et tout d'un coup, nous devons également prendre en charge les fonctionnalités ajoutées dans Development / Prod . C'est juste une bonne quantité de travail et inquiétant pour peu de compromis, mais encore une fois, ce n'est que mon opinion personnelle.

@codedavinci : le but de cette bibliothèque redux-starter-kit est d'ajouter des outils et une abstraction utiles en plus du processus de configuration "de base" du magasin Redux. Notez également qu'il ne s'agit _pas_ du noyau Redux lui-même, mais plutôt d'une bibliothèque distincte que nous aimerions éventuellement faire partie "officielle" de l'organisation Redux.

Tout votre code Redux existant fonctionnera. Tous les tutoriels existants fonctionneront toujours. Nous essayons simplement d'ajouter une approche plus simple officiellement prise en charge pour la configuration et l'utilisation de Redux.

@markerikson Je comprends l'objectif d'avoir le kit de démarrage et je suis tout à fait d'accord pour tout ce qui est mentionné ci-dessus, juste un peu résistant à l'idée d'avoir une bibliothèque comme Immer.js qui change le concept, de la bibliothèque, les gens finiront par apprendre le starter-kit modèles et ignorer complètement les concepts de base. Aucune mutation de magasin n'est la devise, Redux l'a toujours vendu, cela fait partie de la marque.

PS : je comprends parfaitement que Immer.js ne mute rien, mais vous aide plutôt à ne pas le faire, je ne parle que des normes syntaxiques autorisées telles que push , splice ...

Peut-être, c'est juste moi qui résiste aux changements :)

@codeavinci : oui, je comprends l'intérêt des inquiétudes. Pourtant, l'une des plaintes courantes concernant Redux est la douleur d'écrire un code de mise à jour immuable approprié, et Immer est tout simplement la meilleure bibliothèque que j'ai vue pour simplifier ces mises à jour.

@markerikson , j'ai en fait creusé le immer et j'ai remarqué qu'il est très léger, simple et efficace. Je suis en fait vendu :) .

Quel repo rédigez-vous ? celles:

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

Ouais, c'est ça.

@nickmccurdy a un tas de

De beaux progrès @markerikson 👍 J'aime sa simplicité et son efficacité. @nickmccurdy a remarqué que vous êtes très actif sur le projet, j'aimerais discuter avec vous de quelques idées, faites-moi savoir si vous êtes

Bien sûr, merci, il est probablement préférable de démarrer une discussion ouverte dans un nouveau numéro, mais vous pouvez me joindre directement via [email protected] ou sur Discord.

+1 pour le fractionnement de combineReducers . Je l'ai utilisé pendant très longtemps et parce que si c'était le cas, je n'avais pas vraiment réfléchi au fonctionnement de mon magasin.

J'aime actuellement configurer ma fonction de réduction selon les lignes de :

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,
  };
}

Ce qui est quelque chose que combineReducers ne me laisse pas vraiment faire.

@abradley2 : nous ne prévoyons pas de supprimer combineReducers du noyau Redux, si c'est ce que vous demandez. Mais oui, nous avons toujours dit que combineReducers est un utilitaire pour le cas d'utilisation le plus courant, et que vous êtes encouragé à écrire une logique de réduction personnalisée pour votre propre situation.

Nous avons le nom du package redux-starter-kit , et le dépôt a été déplacé dans l'organisation à l' adresse https://github.com/reduxjs/redux-starter-kit . Je vais fermer ce fil. Toute autre discussion peut avoir lieu dans ce dépôt.

De plus, je commence à travailler sur l'ajout de contrôles de mutation et de sérialisation par défaut.

Cette page vous a été utile?
0 / 5 - 0 notes