Redux: RFC: Kit de inicio de Redux

Creado en 1 mar. 2018  ·  56Comentarios  ·  Fuente: reduxjs/redux

Basado en los comentarios en # 2858 y anteriormente en # 2295, suena como un kit de inicio preconfigurado del núcleo de Redux + algunos middleware comunes + mejoradores de tienda + otras herramientas podrían ser útiles para comenzar con la biblioteca.

Comencé reservando un nombre de paquete (aunque no estoy decidido a hacerlo) y podemos comenzar a completar los espacios en blanco allí. Me gustaría mantener el contenido de ese paquete aquí, para que no tengamos que configurar otro repositorio ni nada. Es posible que queramos investigar un monorepo, pero no creo que exista una necesidad urgente actualmente.

Una cosa que me gustaría investigar al mismo tiempo: dividir combineReducers en su propio paquete. Es lo único que se vuelve normativo sobre cómo estructurar y operar una tienda. Obviamente, no es la única forma, pero me preocupa que mucha gente no vea más allá.

En cuanto a lo que incluye un paquete de inicio, la lista corta en mi mente incluye una de las bibliotecas de reducción estándar (o algo que creamos), middleware popular como thunks y sagas, y útiles herramientas de desarrollo. Podríamos tener un paquete de subconjunto para usuarios específicos de React. De hecho, comencé una encuesta en Twitter para averiguar si eso era necesario (¡por favor, RT!).

No creo que necesitemos construir una experiencia similar a la de Create React App con una herramienta CLI y todo ese jazz. Pero algo listo para usar que brinda una excelente experiencia de desarrollo con una mejor depuración y menos código.

discussion ecosystem feedback wanted

Comentario más útil

Entonces, eh ... fui e hice una cosa:

Cosas que son diferentes del fragmento anterior:

  • Lancé una opción de configuración enhancers , solo porque
  • Agregué la dependencia selectorator y exporté createSelector

¿Pensamientos?

Todos 56 comentarios

¡SI SI SI! ¡TENGO MUCHAS OPINIONES Y DESEOS PARA ESTO! Pero me contendré y dejaré que la discusión comience un poco primero.

Un elemento de la lista de deseos que no estoy seguro de que sea factible es el HMR incorporado para los reductores que se agregan automáticamente en una función createReduxStore() . Desafortunadamente, mi conocimiento de Webpack y algo de experimentación dice que eso no es muy factible, porque debe tener rutas codificadas para archivos reductores en las devoluciones module.hot.accept() llamada de Webpack

Entonces, solicitud inicial de comentarios de todos:

  • ¿Cuáles son los requisitos clave que nos gustaría satisfacer con este paquete?
  • ¿Qué paquetes _existentes_ sugeriría para ayudar a cumplir con esos requisitos?
  • ¿Cómo podemos combinar mejor esos paquetes para simplificar las cosas para el usuario final?

Vamos a nombrar 3 puntos clave, donde las posibles variantes estarán _aisladas_ entre sí.

  1. Primer punto. Gerentes reductores
    1.0 Vainilla (¿ES el caso aquí?)
    1.1 Immer.js
    1.2 Coredux
    1.3 100500 paquetes más

  2. Segundo punto. Middlewares
    2.0 vainilla (¿es así?)
    2.1 Sagas
    2.2 Épicas
    2.3 100500 paquetes más.

  3. Tercer punto. Reaccionar integración
    3.0. Vainilla (¿ES el caso aquí?)
    3.1. Subespacio
    3.2 Repetir
    3.3 100500 paquetes más.

Cuarto, bonificación, punto
4.0 Probando todo esto en un _boilerplate_.

Es imposible elegir "los elegidos", por ejemplo, amo y uso tanto Sagas como Epics, pero es posible proporcionar algunos "recibos de cocina" y recomendaciones de combinaciones .

Por ejemplo, la mayoría de los usuarios de redux conocen __sólo__ los middlewares. Una pequeña parte también está haciendo algo con reductores (ok, muchos _oímos sobre immutable.js), solo unos pocos mejoran la integración de React.

El kit de inicio podría ayudar a construir un enfoque completo y rico desde el principio. O uno necesita más de un kit de inicio.

Se le solicitó comentarios sobre los puntos débiles de configuración / repetición en Twitter: https://twitter.com/acemarke/status/969040835508604929

Copiando mi respuesta en twitter:

Me he mantenido explícitamente alejado de agregar el texto estándar de redux ya que, en mi opinión, agrega complejidad al presentar 'su forma' de hacer redux a otra persona. Me encantaría aplicar más convenciones prescriptivas a través de código para hacer de redux una habilidad más portátil.

Con ese fin, tener un repositorio de estilo create-redux-app , sin embargo diseñado más como una biblioteca que como un marco, especialmente uno respaldado explícitamente por los mantenedores de las mejores y recomendadas prácticas de Redux, creo que contribuiría en gran medida a solidificar y agregar claridad sobre el uso adecuado de Redux.

Hemos estado hablando un poco sobre esto en Reactiflux, queríamos copiar una consolidación de los deseos de inclusión en este hilo, algo de esto se superpone con los puntos que ya enumeraste @timdorr (por lo que es una confirmación entusiasta).

  1. wrapper around createStore con mejores valores predeterminados, es decir, una forma más fácil de agregar middleware, herramientas de desarrollo redux
  2. construido en ayudante inmutable (immer?)
  3. createReducer integrado (la utilidad estándar de "tabla de búsqueda de reductores")
  4. volver a seleccionar incorporado
  5. creador de acciones que se adhiere a FSA
  6. Soporte de acción asíncrona / soporte de efectos secundarios (flujo, saga, ¿qué?)

¿Por qué no respaldar oficialmente algo que ya existe, como el redux-bundler de Henrik Joreteg?

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

Es conciso, obstinado (en el buen sentido), permite la reutilización de la funcionalidad relacionada con redux en todas las aplicaciones y aún ofrece una buena solución para el manejo asíncrono.

Es un proyecto de aspecto fascinante, y uno que realmente quiero investigar más a fondo, pero también está fuera del alcance de lo que quiero hacer con esta tarea.

Lo que realmente quiero lograr aquí es:

  • Configurar una tienda Redux con un par de líneas de código y opciones de configuración mínimas necesarias (el equivalente Redux del lema "JS de configuración cero" que Webpack y Parcel han estado usando).
  • Similar a CRA, las cosas de configuración están básicamente ocultas, con buenos valores predeterminados listos para usar
  • Inclusión de paquetes cuidadosamente seleccionados para mejorar la experiencia de los desarrolladores y, sí, "reducir el texto estándar". Por ejemplo, Immer sería una gran opción porque simplifica drásticamente la escritura de la lógica reductora inmutable _y_ congela su estado en dev. (Mi única duda es que la apariencia del código que está "mutando" sería confusa).

Quiero mantener este esfuerzo en un ámbito bastante estricto. He estado charlando con @hswolff y @nickmccurdy en Reactiflux las últimas horas, y aunque la discusión ha sido excelente, ya hemos analizado una docena de casos de uso e ideas superpuestos que realmente podrían complicar demasiado las cosas.

Quiero obtener _algo_ útil, valioso y viable ensamblado sin demasiada pérdida de bicicletas, y luego tener otras discusiones a un lado (como una API para hacer "paquetes" o "módulos" de Redux, etc.).

Para comenzar con una repetición inicial de las API, aquí hay una idea básica para 1-3 de mi lista que publiqué anteriormente:

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

Sí, me encanta eso. Entonces esperaría que siempre agregara thunk() al principio de la lista de middleware, o posiblemente solo si no proporcionó ningún middleware usted mismo. Es posible que ni siquiera queramos permitir que el usuario especifique potenciadores aquí. Agregaríamos applyMiddleware() automáticamente si hay algún middleware, y usaríamos la función composeWithDevtools de redux-devtools-extension if devTools : true . Para los propósitos de esta "configuración fácil", creo que es posible que queramos eliminar los "mejoradores" de las cosas que el usuario puede configurar.

+1 en la eliminación de potenciadores.

En su punto de que el procesador se agregue automáticamente, deberíamos poder tener nuestro pastel y comerlo también mediante la exportación de la función que usaríamos para agregar el middleware predeterminado:

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

Sí, eso es más o menos lo que estaba pensando. Mi principal preocupación es averiguar si el usuario intenta accidentalmente proporcionar su propia instancia de thunk .

Decidí jugar un poco con las cosas esta noche. Aquí tienes un primer corte. ¿Pensamientos?

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

Y el ejemplo obligatorio de la aplicación de tareas pendientes:

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

Creo que este es un comienzo sólido y un gran comienzo para la biblioteca que se está discutiendo en este hilo. Cubre los puntos 1, 2, 3 y 6 de mi lista de características deseadas anterior.

Iterar sobre esto sería genial, pero esta es una base sólida.

En lugar de centrarnos en la implementación, me gustaría que nos centramos en el DX. ¿Qué son las exportaciones / API y cómo se utilizan? Creo que es una gran oportunidad para superar la configuración y también ver cómo la gente usa la tienda. Algunas ideas aleatorias:

Pares de acción / reductor más fáciles:

Haga que sea muy fácil emparejar sus reductores y acciones junto con su salida de estado. Esto es aproximado, pero esta es la idea básica:

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

Tienda Singleton

Este no me convence de ninguna manera, pero estaba pensando en los días en que teníamos singleton históricos en React Router. No fue perfecto, pero proporcionó algo de valor.

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

configureStore(reducer, middleware, initialState)

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

Configurabilidad a través de import

Dejaré lo más loco para el final. Pero, ¿y si permitiéramos la configuración mediante la importación de archivos? Necesitaríamos algunos pases globales detrás de escena, lo que se vuelve complicado / problemático. Pero, de nuevo, la atención se centra en el usuario, no en nuestro lado.

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'

Para ese segundo ejemplo, puedo ver a los usuarios usando un alias para ese paquete en sus herramientas de compilación o haciendo algo como lo que hace React .

De acuerdo, eso es todo de mi parte por ahora. Una vez más, quiero pensar primero en el usuario. Cualquier truco sucio y feo que tengamos que hacer para implementar esto es irrelevante. El punto es un gran DX con menos código escrito y menos configuración necesaria.

Amo estas ideas hasta ahora. Mi único deseo para lo que sea que esto resulte sería un acceso elegante al nivel inferior, la API estándar de Redux. Debe haber un camino natural para que las personas personalicen o expulsen. Ya sea en unos días o en un año o dos, debería ser simple. El bloqueo es uno de los problemas que veo (de mi propio intento con Jumpstate y de bibliotecas más recientes como Rematch). Cuanto más podamos evitar eso, mejor sabor tendrá la gente en la boca :)

Sí, he visto bastantes bibliotecas de utilidades que hacen cosas como ese "paquete de acción" (al menos en lo que respecta al aspecto de "escribir algunos reductores, convertir las claves en tipos de acción y creadores de acciones"), y estaba considerando lanzar eso como un elemento adicional, simplemente no había llegado allí todavía. No estoy seguro sobre el aspecto "combineActionPack".

Anoche tuve una discusión adicional con selectores , que parece ser un superconjunto de la API Reselect con algunos beneficios útiles adicionales:

import createSelector from 'selectorator';

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

Eso ayudaría a reducir muchos de los selectores de "entrada simple" escritos a mano, como const selectTodos = state => state.todos .

No estoy seguro de ver el beneficio de agregar una biblioteca de selectores. También tendríamos que proporcionar alguna opinión sobre la forma del estado que permite.

Es al menos en parte solo para que haya un elemento menos que el usuario debe instalar en package.json .

Creo que una biblioteca de selectores sería increíble.

También relevante: el artículo reciente sobre el kit de inicio apollo-boost

Si podemos extender la API de connect react-redux para usar reselect (o una biblioteca de selector similar) cuando mapStateToProps es un Array , podríamos Fomente el uso de selectores y hágalo muy conveniente sin romper la compatibilidad. No creo que esta biblioteca deba combinarse con React o react-redux necesariamente, pero tal vez podamos manejar esa extensibilidad a través de una opción por react-redux o proporcionar otro paquete que envuelva el kit de inicio con react-redux soporte.

Sí, no estoy buscando hacer nada con React-Redux para este MVP inicial.

En ese caso, ¿hay una buena manera de agregar una abstracción para los selectores en el nivel de Redux o es algo que solo podríamos hacer de manera efectiva además de react-redux? El problema es que no queremos que esto sea incompatible con react-redux, así que supongo que si eso no es posible, deberíamos deshacernos de los selectores por ahora.

Siempre que implemente la API de la tienda, será compatible con react-redux. No buscamos romper esa API, solo mejorar DX.

Eso tiene sentido. No he usado selectores fuera de react-redux, así que me preguntaba si serían aplicables a la configuración de Redux aquí.

@timdorr +1 en el deseo expresado con pares de acción / reductor más fáciles. También me encantaría presentar alguna forma de facilitar la creación de un módulo redux (también conocido como el patrón de patos) de modo que crear un reductor, creadores de acciones y selectores sea una experiencia mucho más agradable y fácil de usar.

Creo que encontrar una solución a ese problema que hace feliz a la mayoría de las personas requerirá un poco más de desprendimiento de bicicletas y me pregunto si es algo que podamos agregar en una versión de seguimiento para que no bloquee una inicial. liberación.

Creo que lo que @markerikson creó en su comentario ya reduce una gran cantidad de texto estándar y sería una excelente versión preliminar inicial.

Después de eso, podemos abordar los otros aspectos de Redux que son engorrosos (creación de redux / acción / selector).

Creo que tratar de resolver todos los problemas desde el principio va a obstaculizar cualquier forma de progreso tangible.

Si cree que está lo suficientemente listo, creo que sería una buena idea iniciar un repositorio para que podamos probar esta configuración con un código de ejemplo y probarlo un poco (o tal vez un paquete en una rama de funciones de monorepo, y podríamos colaborar a través de RRPP).

Seguro. Veré si puedo configurar algo un poco más tarde hoy.

No necesitamos otro repositorio. Este existirá dentro del actual. Por favor, primero haga un PR.

¿Debería ser parte del paquete principal redux como una importación separada (por lo que es completamente compatible con versiones anteriores) o preferiría un monorepo con varios paquetes? Creo que lo primero sería suficiente, siempre podríamos usar otro archivo de exportación sin crear un nuevo paquete si se vuelve demasiado grande.

Me gustaría jugar con esto como un repositorio / paquete separado para empezar, de verdad.

Puede ser más fácil usar la configuración de herramientas existente en este repositorio, ya que fusionarlo en el futuro podría ser propenso a errores. Probablemente tampoco necesitemos soporte de sintaxis diferente porque no estamos haciendo que este React sea específico.

Si va a ser un solo archivo con alguna preconfiguración, lo más fácil sería mantenerlo aquí. Debido a las dependencias, debería ser un paquete separado. No queremos cargar con esas aplicaciones existentes.

Nuevamente, no creo que debamos ir a monorepo, pero podemos tener una carpeta para compilaciones empaquetadas específicas si comenzamos a compilar más de una. Solo una carpeta starter por ahora con su propio package.json debería funcionar.

Me gusta la idea de mantener este local en el paquete principal de redux si solo está usando código local para redux. Me vuelvo más indeciso si comenzamos a incorporar dependencias externas para respaldar las ideas expresadas aquí.

Creo que algunas dependencias externas como immer, thunk / promise / saga y reselect serían invaluables para nuestros objetivos aquí y valdrían la pena las dependencias adicionales para el motor de arranque, aunque es posible que no queramos esas dependencias en el paquete principal redux . .

Entonces, eh ... fui e hice una cosa:

Cosas que son diferentes del fragmento anterior:

  • Lancé una opción de configuración enhancers , solo porque
  • Agregué la dependencia selectorator y exporté createSelector

¿Pensamientos?

Como alguien que acaba de aprender Redux (y React) por mí mismo en las últimas semanas, no puedo esperar a ver el producto final. Estoy seguro de que voy a tener un montón de cosas que limpiar en mi código.

😏 👍

Entonces, como la idea larga es simplificar el uso de redux, podría proponer 2 momentos:

  1. Agregue la función incorporada literalmente a expect(mapStateToProps(state)).toEqual(mapStateToProps(state)) . Solo para animar a la gente a crear un código mejor. Nunca vi pruebas como esta, pero _not-very-pure_ mapStateToProps es uno de los problemas de reducción.

  2. Considere la adopción de algo así como memorizar el estado . Es como Immer.js para selectores. El punto clave: el cliente puede simplemente escribir mapStateToProps o selector en la forma que prefiera y memorizarlo. Incluso podría resolver este problema de reselección con "Compartir selectores con accesorios en varias instancias de componentes" sin perder la memorización "común" entre instancias. Solo memoriza dos veces las cosas

  1. Veo lo que quiere decir en términos de recomendar selectores puros, pero un selector idempotente impuro aún podría pasar esa prueba. Me gusta más la segunda sugerencia.
  2. Eso suena genial, así que simplemente envolvemos los selectores de la misma manera que envolvemos los reductores para inmersión, ¿verdad?

Aún así, como discutimos anteriormente, esto es más una cosa de react-redux que algo que estaría en el paquete de inicio que es independiente de React.

¡Esto es realmente genial!

Sin embargo, tengo una solicitud / comentario; Preferiría que Immer no se usara implícitamente.

Immer es genial . Se ha convertido en una de mis utilidades favoritas. Pero incluso cuando lo uso explícitamente ( produce(baseState, draftState => ... ), me preocupa cuando otras personas que no están familiarizadas con él ven mi código y no me dan cuenta de que solo puedo hacer estas cosas mutativas debido a los superpoderes de Immer.

De la forma en que se ve la API ahora, puedo imaginar a los recién llegados sin darse cuenta de que el estado de redux debería ser inmutable. Creo que los malentendidos los morderían mucho cuando intentaran usar Redux sin este kit de inicio.

Veo que createNextState ya es una exportación, así que ¿por qué no animar a los usuarios a usarlo explícitamente?

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

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

(¡Disculpas si he entendido mal cómo se pretende usar createNextState ! No lo he investigado en absoluto)

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

De la forma en que se ve la API ahora, puedo imaginar a los recién llegados sin darse cuenta de que el estado de redux debería ser inmutable. Creo que los malentendidos los morderían mucho cuando intentaran usar Redux sin este kit de inicio.

En mi opinión, deberíamos recomendar no usar Redux directamente a favor de este paquete cuando esté completo debido a https://github.com/reactjs/redux/issues/2858. Básicamente, queremos advertir o proteger a los usuarios de todas las mutaciones de forma predeterminada, pero no podemos hacer esto fácilmente en el núcleo sin romper las cosas, por lo que deberíamos recomendar no usar el núcleo, excepto en los casos extremos donde el kit de inicio no es suficiente. Esto es similar a cómo React recomienda CRA y Redux recomienda react-redux cuando se usa React.

Veo que createNextState ya es una exportación, entonces, ¿por qué no animar a los usuarios a usarlo explícitamente?

No es una mala idea, pero creo que estamos más a favor de estar implícitos aquí, especialmente porque no estamos generando código fuente y la adición de immer es compatible con versiones anteriores.

Veo a mucha gente recomendando usar libs como immer.js , que desde mi humilde opinión consiste en desviar sin saberlo la motivación de aprender y respetar los requisitos de store .

Todos sabemos que la tienda no puede ser mutada, por lo tanto, preferiría tener un mecanismo de validación donde verifique la instancia newState con ( === ) el previousState y si es la misma instancia arroja un error.

De esta manera, todos tendrían que aprender las reglas y requisitos de store .

PD: Realmente entiendo el beneficio de immer y no tengo absolutamente nada en contra, pero estamos llegando a un momento en el que la gente finalmente comprende el concepto, generaría una gran fuente de confusión y técnicamente diría: si lo comparamos, no haríamos nada más que agregar una capa adicional de complejidad solo para aflojar la biblioteca.

Sugerencias personales:

Los logger , devTools y Thunk deben agregarse como valor predeterminado del Starter , el resto creo que es más una elección personal.

Todos sabemos que la tienda no puede ser mutada, por lo tanto, preferiría tener un mecanismo de validación en el que verifique la instancia newState con (===) previousState y, si es la misma instancia, arroje un error.

Hay casos en los que, dependiendo de la acción, no querrá que cambie el estado, por lo que devolvería la misma instancia de tienda para ahorrar memoria y evitar diferencias falsas positivas. Incluso si solucionamos este problema, parece que Redux no quiere un validador en el núcleo y creo que Immer es una buena protección para esto personalmente. Estoy de acuerdo en que es como frustrar el propósito de aprender Redux hasta cierto punto, pero veo tantos desarrolladores aprendiendo Redux que no quieren aprender FP puro o no son conscientes de ello.

si lo comparamos, no haríamos nada más que agregar una capa adicional de complejidad solo para aflojar la biblioteca.

Hasta donde yo sé, la forma en que Immer se implementa, el Proxy solo tiene una sobrecarga de rendimiento si realmente está mutado, por lo que los reductores de actualización inmutables típicos no deberían tener una sobrecarga de rendimiento. Creo que este es un buen equilibrio.

El registrador, devTools y Thunk deben agregarse por defecto del Starter, el resto creo que es más una elección personal.

Hay algunas otras cosas que me gustaría considerar eliminar (aunque personalmente no veo una gran ventaja para el registrador sobre las herramientas de desarrollo que compensa su sobrecarga de rendimiento), consulte https://github.com/markerikson/ redux-starter-kit / issues / 19. Sin embargo, no estoy en contra de agregar más cosas si son compatibles con versiones anteriores, como nuestro uso actual de Immer y Thunk.

Hay casos en los que, dependiendo de la acción, no querrá que cambie el estado, por lo que devolvería la misma instancia de tienda para ahorrar memoria y evitar diferencias falsas positivas. Incluso si solucionamos este problema, parece que Redux no quiere un validador en el núcleo y creo que Immer es una buena protección para esto personalmente. Estoy de acuerdo en que es como frustrar el propósito de aprender Redux hasta cierto punto, pero veo tantos desarrolladores aprendiendo Redux que no quieren aprender FP puro o no son conscientes de ello.

@nickmccurdy Entiendo totalmente su punto de vista, y estoy de acuerdo en que no deberíamos tener una obstrucción en el aprendizaje debido a algunos conceptos de FP, Mutación, etc. Pero como educador, creo firmemente en no endulzar al aprendiz con ocultando la complejidad de ellos. De todos modos, es solo una cuestión de gustos, soy un profesional que aprende y avanza, y al mirar esta propuesta, mi instinto de alguna manera me dice que estaríamos avanzando con aceptación, pero retrocediendo con los estándares. Solo en la nota, piense en todo el contenido en la web en este momento que enseña los Estándares de Redux y cómo finalmente se está recuperando.

Hasta donde yo sé, la forma en que Immer se implementa, el Proxy solo tiene una sobrecarga de rendimiento si realmente está mutado, por lo que los reductores de actualización inmutables típicos no deberían tener una sobrecarga de rendimiento. Creo que este es un buen equilibrio.

Cuando me refiero a agregar una capa de complejidad, me refiero a que Immer nunca ha estado allí y ahora podría serlo, tendríamos que admitirlo en la biblioteca, probarlo, evaluar problemas de rendimiento y, por último, pero no menos importante esta sección aquí, me da aprensión:

Immer.js - Congelación automática
Immer congela automáticamente los árboles de estado que se modifican con productos. Esto protege contra modificaciones accidentales del árbol de estado fuera de un productor. Esto tiene un impacto en el rendimiento, por lo que se recomienda deshabilitar esta opción en producción. Está habilitado de forma predeterminada. De forma predeterminada, se enciende durante el desarrollo local y se apaga en producción. Utilice setAutoFreeze (verdadero / falso) para activar o desactivar explícitamente esta función.

Y, de repente, ahora también necesitamos admitir funciones agregadas en Development / Prod . Es solo una buena cantidad de trabajo y preocupante por no tener mucho que sacrificar, pero nuevamente, esta es solo mi opinión personal.

@codedavinci : el objetivo de esta biblioteca redux-starter-kit es agregar herramientas útiles y abstracción sobre el proceso "básico" de configuración de la tienda Redux. Además, tenga en cuenta que esto _no_ va al núcleo de Redux en sí, sino a una biblioteca separada que nos gustaría convertir en una parte "oficial" de la organización de Redux eventualmente.

Todo su código de Redux existente funcionará. Todos los tutoriales existentes seguirán estando bien. Solo estamos tratando de agregar un enfoque más simple con soporte oficial para configurar y usar Redux.

@markerikson Entiendo el objetivo de tener el kit de inicio y estoy completamente decepcionado por todo lo mencionado anteriormente, solo un poco resistente a tener una biblioteca como Immer.js que cambia el concepto, de la biblioteca, la gente eventualmente aprenderá el starter-kit patrones e ignore por completo los conceptos básicos. Ninguna mutación de tienda es el lema, Redux siempre lo ha estado vendiendo, es parte de la marca.

PD: Entiendo completamente que Immer.js no cambia nada, sino que te ayuda a no hacerlo, solo estoy hablando de estándares sintácticos permitidos como push , splice ...

Tal vez, solo soy yo el que me resiste a los cambios :)

@codedavinci : sí, entiendo el punto de las preocupaciones. Aún así, una de las quejas comunes sobre Redux es el dolor de escribir un código de actualización inmutable adecuado, e Immer es simplemente la mejor biblioteca que he visto para simplificar esas actualizaciones.

@markerikson , de hecho investigué un poco el immer y noté que es muy ligero, simple y eficiente. De hecho, estoy vendido :).

¿Qué repositorio estás redactando? aquellos:

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

Sí, eso es todo.

@nickmccurdy tiene un montón de relaciones públicas esperando discusión y fusión, principalmente en torno a herramientas, pero también algo de discusión sobre cómo queremos enfocar el proyecto a largo plazo. Necesito empezar a verlos, pero he estado ocupado con otras cosas las últimas dos semanas (incluida la charla de la conferencia que daré mañana).

Gran progreso @nickmccurdy & @markerikson 👍 Me encanta su sencillez y eficacia. @nickmccurdy notó que eres muy activo en el proyecto, me encantaría tener una charla contigo sobre algunas ideas, ¡avísame si estás dispuesto a hacerlo! :)

Claro, gracias, probablemente sea mejor comenzar una discusión abierta sobre un nuevo número, pero puede comunicarse conmigo directamente a través de [email protected] o en Discord.

+1 por dividir combineReducers . Lo usé durante más tiempo y porque si lo hacía, realmente no pensaba profundamente en cómo funcionaba mi tienda.

Actualmente me gusta configurar mi función reductora en las líneas 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,
  };
}

Lo cual es algo que combineReducers realmente no me deja hacer.

@ abradley2 : no estamos planeando eliminar combineReducers del núcleo de Redux, si eso es lo que estás preguntando. Pero sí, siempre hemos dicho que combineReducers es una utilidad para el caso de uso más común, y que le recomendamos que escriba una lógica de reducción personalizada para su propia situación.

Tenemos el nombre del paquete redux-starter-kit y el repositorio se ha movido a la organización en https://github.com/reduxjs/redux-starter-kit . Voy a cerrar este hilo. Cualquier discusión adicional puede ocurrir en ese repositorio.

Además, estoy empezando a trabajar para agregar verificaciones de mutaciones y serializabilidad de forma predeterminada.

¿Fue útil esta página
0 / 5 - 0 calificaciones