Redux: RFC: Redux Starter Kit

Criado em 1 mar. 2018  ·  56Comentários  ·  Fonte: reduxjs/redux

Com base nos comentários em # 2858 e anteriores em # 2295, parece um kit inicial pré-configurado do núcleo Redux + algum middleware comum + aprimoradores de loja + outras ferramentas podem ser úteis para começar com a biblioteca.

Comecei reservando um nome de pacote (embora não esteja totalmente decidido a isso) e podemos começar a preencher os espaços em branco lá. Eu gostaria de manter o conteúdo desse pacote aqui, então não temos que configurar outro repo ou algo assim. Podemos querer investigar um monorepo, mas não acho que haja uma necessidade urgente no momento.

Uma coisa que eu gostaria de investigar ao mesmo tempo: dividir combineReducers em seu próprio pacote. É a única coisa que se torna prescritiva sobre como estruturar e operar uma loja. Obviamente não é a única maneira, mas me preocupo que muitas pessoas não enxerguem além dela.

Quanto ao que vem em um pacote inicial, a pequena lista em minha mente inclui uma das bibliotecas de redução padrão (ou algo que construímos), middleware popular como thunks e sagas e ferramentas de desenvolvimento úteis. Poderíamos ter um pacote de subconjunto para usuários específicos do React. Na verdade, eu comecei uma enquete no Twitter para descobrir se isso é mesmo necessário (por favor, RT!).

Não acho que precisamos construir uma experiência semelhante ao Create React App com uma ferramenta CLI e todo esse jazz. Mas algo fora da caixa que oferece uma ótima experiência de desenvolvimento com melhor depuração e menos código.

discussion ecosystem feedback wanted

Comentários muito úteis

Então, uh ... eu fui e fiz uma coisa:

Coisas que são diferentes do snippet anterior:

  • Eu coloquei uma opção de configuração enhancers , só porque
  • Eu adicionei a dependência selectorator e exportei createSelector

Pensamentos?

Todos 56 comentários

SIM SIM SIM! TENHO MUITAS OPINIÕES E DESEJOS PARA ISSO! Mas vou me conter e deixar a discussão começar um pouco primeiro.

Um item da lista de desejos que eu não tenho certeza se é viável é o HMR integrado para redutores automaticamente adicionado em uma função createReduxStore() . Infelizmente, meu conhecimento do Webpack e alguns experimentos dizem que isso não é muito viável, porque você precisa ter caminhos codificados para arquivos redutores nos retornos de chamada do Webpack module.hot.accept() . Não tenho certeza de como Parcel ou outros empacotadores lidam com isso.

Portanto, pedido inicial de feedback de todos:

  • Quais são os principais requisitos que gostaríamos de satisfazer com este pacote?
  • Quais pacotes _existentes_ você sugeriria para ajudar a cumprir esses requisitos?
  • Como podemos combinar melhor esses pacotes para manter as coisas simples para o usuário final?

Vamos citar três pontos-chave, onde as possíveis variantes serão _isoladas_ umas das outras.

  1. Primeiro ponto. Gerentes redutores
    1.0 Vanilla (é o caso aqui?)
    1.1 Immer.js
    1.2 Coredux
    1.3 100500 mais pacotes

  2. Segundo ponto. Middlewares
    2.0 Vanilla (é o caso?)
    2.1 Sagas
    2.2 Epopéia
    2.3 100500 mais pacotes.

  3. Terceiro ponto. Integração de reação
    3.0. Vanilla (é o caso aqui?)
    3.1. Subespaço
    3.2 Reafirmar
    3,3 100500 mais pacotes.

4º, bônus, ponto
4.0 Testando tudo isso em um _boilerplate_.

É impossível escolher "os escolhidos", por exemplo, adoro e uso tanto Sagas como Epopeias, mas é possível fornecer alguns "recibos de cozinha" e recomendações de combinações .

Por exemplo, a maioria dos usuários redux está ciente __apenas__ sobre middlewares. Uma pequena parte também fazendo algo com redutores (ok, muitos _heard_ sobre immutable.js), apenas alguns aprimoram a integração do React.

O Starter Kit pode ajudar a construir uma abordagem completa e _riquecida_ desde o início. Ou um precisa mais de um Starter Kit.

Solicitado feedback sobre pontos de dor de configuração / boilerplate no Twitter: https://twitter.com/acemarke/status/969040835508604929

Copiando minha resposta no twitter:

Eu evitei explicitamente adicionar redux boilerplate como IMO, ele adiciona complexidade ao apresentar 'sua maneira' de redux para outra pessoa. Eu adoraria convenções mais prescritivas impostas por meio de código para tornar o redux uma habilidade mais portátil.

Para esse fim, ter um repositório no estilo create-redux-app - no entanto, projetado mais como uma biblioteca do que um framework - especialmente um explicitamente endossado pelos mantenedores do Redux das práticas recomendadas e recomendadas, acho que seria um longo caminho para solidificar e adicionar clareza sobre o uso adequado do Redux.

Falamos um pouco sobre isso no Reactiflux, queria copiar uma consolidação de desejos de inclusão neste tópico, alguns desses pontos se sobrepõem aos pontos que você já listou @timdorr (por isso é uma confirmação entusiástica).

  1. envolva o createStore com melhores padrões, ou seja, uma maneira mais fácil de adicionar middleware, ferramentas redux dev
  2. construído em ajudante imutável (immer?)
  3. createReducer integrado (o utilitário padrão de "tabela de pesquisa de redutor")
  4. selecionar novamente integrado
  5. criador de ação que segue a FSA
  6. suporte a ação assíncrona / suporte a efeitos colaterais (fluxo, saga, o quê?)

Por que não apoiar oficialmente algo que já existe, como o redux-bundler de Henrik Joreteg?

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

É conciso, opinativo (no bom sentido), permite a reutilização da funcionalidade relacionada ao redux entre aplicativos e ainda oferece uma boa solução para o manuseio assíncrono.

É um projeto de aparência fascinante e que eu realmente quero investigar mais a fundo, mas também está fora do escopo do que quero fazer com esta tarefa.

O que eu realmente quero realizar aqui é:

  • Configurando uma loja Redux com algumas linhas de código e escolhas mínimas de configuração necessárias (o Redux equivalente ao tagline "zero-config JS" que Webpack e Parcel têm usado).
  • Semelhante ao CRA, o material de configuração está basicamente oculto, com bons padrões prontos para uso
  • Inclusão de pacotes cuidadosamente selecionados para melhorar a experiência de desenvolvimento e, sim, "reduzir o boilerplate". Por exemplo, o Immer seria uma ótima escolha porque simplifica drasticamente a escrita da lógica do redutor imutável _e_ congela seu estado no dev. (Minha única hesitação é que a aparência do código em "mutação" seria confusa.)

Eu quero manter esse esforço com um escopo bem restrito. Estive conversando com @hswolff e @nickmccurdy no Reactiflux nas últimas duas horas e, embora a discussão tenha sido ótima, já examinamos uma dúzia de casos de uso e ideias sobrepostos que podem realmente complicar as coisas.

Eu quero reunir _algo_ útil, valioso e viável sem muitos passeios de bicicleta, e então ter outras discussões de lado (como uma API para fazer Redux "pacotes" ou "módulos", etc).

Para lançar um boilerplating inicial de APIs, aqui está uma ideia básica para 1-3 da minha lista que postei acima:

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

Sim, eu gosto disso. Eu então esperaria que ele sempre adicionasse thunk() no início da lista de middleware, ou possivelmente apenas se você não forneceu nenhum middleware. Podemos nem mesmo permitir que o usuário especifique realçadores aqui. Adicionaríamos applyMiddleware() automaticamente se houver algum middleware e usaríamos a função composeWithDevtools de redux-devtools-extension se devTools : true . Para fins de "configuração fácil", acho que podemos eliminar "realçadores" das coisas que o usuário pode configurar.

+1 na eliminação de realçadores.

Em seu ponto de vista sendo adicionado automaticamente, devemos ser capazes de ter nosso bolo e comê-lo exportando a função que usaríamos para adicionar o middleware padrão:

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

Sim, era mais ou menos o que eu estava pensando. Minha principal preocupação é descobrir se o usuário acidentalmente tenta fornecer sua própria instância de thunk .

Decidi brincar um pouco com as coisas esta noite. Aqui está um primeiro corte. Pensamentos?

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

E o exemplo de aplicativo de tarefas obrigatório:

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

Acho que este é um começo sólido e um ótimo começo para a lib que está sendo discutida neste tópico. Abrange os pontos 1,2,3 e 6 da minha lista de recursos desejados acima.

Repetir isso seria ótimo, mas essa é uma base sólida.

Em vez de focar na implementação, gostaria que nos concentrássemos no DX. O que são exportações / APIs e como são usadas? Acho que é uma ótima chance de superar apenas a configuração e também ver como as pessoas usam a loja. Algumas ideias aleatórias:

Pares redutor / ação mais fáceis:

Torne muito fácil emparelhar seus redutores e ações junto com sua saída de estado. Isso é difícil, mas aqui está a ideia 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!'))

Store Singleton

Este eu não estou convencido de forma alguma, mas eu estava pensando nos dias em que tínhamos singletons de história no React Router. Não era perfeito, mas forneceu algum valor.

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

configureStore(reducer, middleware, initialState)

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

Configurabilidade via import

Vou deixar meu maluco para o final. Mas e se permitíssemos a configuração importando arquivos. Precisaríamos de uma passagem global nos bastidores, o que fica confuso / problemático. Mas, novamente, o foco está no usuário, não do nosso 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 aquele segundo exemplo, posso ver os usuários criando um alias para esse pacote em suas ferramentas de construção ou fazendo algo parecido com o que o React faz .

OK, é isso de mim por agora. Mais uma vez, quero pensar primeiro no usuário. Quaisquer hacks sujos e feios que tenhamos que fazer para implementar isso são irrelevantes. A questão toda é um ótimo DX com menos código escrito e menos configuração necessária.

Amei essas idéias até agora. Meu único desejo para o que quer que seja, seria um acesso elegante ao nível inferior, a API Redux padrão. Deve haver um caminho natural para as pessoas personalizarem ou ejetarem. Quer seja em alguns dias, ou um ano ou dois, deve ser simples. O lock-in é um dos problemas que vejo (de minha própria tentativa com o Jumpstate e de bibliotecas mais recentes como Rematch). Quanto mais pudermos evitar isso, melhor sabor as pessoas terão na boca :)

Sim, eu vi alguns util libs que fazem coisas como aquele "pacote de ação" (pelo menos no que diz respeito ao aspecto "escrever alguns redutores, transformar as chaves em tipos de ação e criadores de ação") e estava pensando em jogar isso como um item adicional - só não tinha chegado lá ainda. Não tenho certeza sobre o aspecto "combineActionPack".

Tive alguma discussão adicional com @hswolff ontem à noite. Eu gostaria de considerar adicionar / reexportar a biblioteca do seletor , que parece ser um superconjunto da API Reselect com alguns benefícios adicionais úteis:

import createSelector from 'selectorator';

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

Isso ajudaria a reduzir muitos dos seletores de "entrada simples" escritos à mão, como const selectTodos = state => state.todos .

Não tenho certeza se vejo a vantagem de adicionar uma biblioteca de seletores. Teríamos que fornecer também alguma opinião sobre a forma de estado que é habilitada por ele.

É pelo menos parcialmente apenas para que haja um item a menos que o usuário deve instalar em package.json .

Eu acho que uma biblioteca de seletores seria incrível.

Também relevante: o artigo recente sobre o kit inicial apollo-boost

Se pudermos estender react-redux 's connect ' s API para usar reselect (ou uma biblioteca de seletor semelhante) quando mapStateToProps é um Array , poderíamos encoraje o uso de seletores e torne-o muito conveniente sem quebrar a compatibilidade. Não acho que esta biblioteca deva ser acoplada com React ou react-redux necessariamente, mas talvez pudéssemos lidar com essa extensibilidade por meio de uma opção de react-redux ou fornecer outro pacote envolvendo o kit inicial com react-redux Suporte para

Sim, não estou procurando fazer nada com React-Redux para este MVP inicial.

Nesse caso, há uma boa maneira de adicionar uma abstração para seletores no nível Redux ou isso é algo que só poderíamos fazer efetivamente em cima do react-redux? O problema é que não queremos que isso seja incompatível com o react-redux, então acho que se isso não for possível, devemos abandonar os seletores por enquanto.

Contanto que implemente a API da loja, é compatível com o react-redux. Não queremos quebrar essa API, apenas melhorar o DX.

Isso faz sentido. Eu não usei seletores fora do react-redux, então queria saber se eles seriam aplicáveis ​​para configurar o próprio Redux aqui.

@timdorr +1 no desejo expresso com pares redutor / ação mais fáceis. Eu também adoraria apresentar uma maneira de tornar mais fácil a criação de um módulo redux (também conhecido como padrão patos), de forma que criar um redutor, criadores de ação e seletores seja uma experiência muito mais agradável e fácil de usar.

Acho que encontrar uma solução para esse problema que deixa a maioria das pessoas feliz exigirá um pouco mais de troca de bicicletas e estou me perguntando se é algo que podemos adicionar em uma versão posterior para que não bloqueie uma inicial liberar.

Acho que o que @markerikson criou em seu comentário já reduz bastante o padrão e seria um ótimo pré-lançamento inicial.

Depois disso, podemos lidar com os outros aspectos do Redux que são complicados (redux / ação / criação do seletor).

Acho que tentar resolver todos os problemas com antecedência vai atrapalhar qualquer forma de progresso tangível.

Se você acha que está pronto o suficiente, acho que seria uma boa ideia iniciar um repositório para que possamos testar esta configuração com código de exemplo e dogfood um pouco (ou talvez um pacote em um branch de recurso do monorepo, e poderíamos colaborar por meio de RP).

Certo. Vou ver se consigo configurar algo um pouco mais tarde hoje.

Não precisamos de outro repositório. Isso existirá dentro do atual. Por favor, faça de qualquer coisa um PR primeiro.

Isso deve fazer parte do pacote principal redux como uma importação separada (para que seja totalmente compatível) ou você prefere um monorepo com vários pacotes? Acho que o primeiro seria o suficiente, sempre poderíamos usar outra exportação de arquivo sem criar um novo pacote se ele ficar muito grande.

Eu meio que gostaria de brincar com isso como um repositório / pacote separado para começar, na verdade.

Pode ser mais fácil usar a configuração de ferramentas existente neste repositório, uma vez que mesclá-la novamente no futuro pode estar sujeita a erros. Provavelmente também não precisamos de suporte de sintaxe diferente, porque não estamos tornando este React específico.

Se for um único arquivo com alguma pré-configuração, mantê-lo aqui seria mais fácil. Por causa das dependências, deve ser um pacote separado. Não queremos sobrecarregar os aplicativos existentes com eles.

Novamente, não acho que precisamos ir monorepo, mas podemos ter uma pasta para compilações específicas empacotadas se começarmos a construir mais de uma. Apenas uma pasta starter por enquanto com seu próprio package.json deve resolver o problema.

Eu gosto da ideia de manter este local no pacote redux principal se ele estiver usando apenas o código local para reduxar em si. Fico mais hesitante se começarmos a incluir dependências externas para dar suporte às ideias expressas aqui.

Acho que algumas dependências externas como immer, thunk / promessa / saga e re-seleção seriam inestimáveis ​​para nossos objetivos aqui e valem as dependências extras para o iniciador, embora possamos não querer essas dependências no próprio pacote redux .

Então, uh ... eu fui e fiz uma coisa:

Coisas que são diferentes do snippet anterior:

  • Eu coloquei uma opção de configuração enhancers , só porque
  • Eu adicionei a dependência selectorator e exportei createSelector

Pensamentos?

Como alguém que aprendeu Redux (e React) nas últimas semanas, mal posso esperar para ver o produto final. Tenho certeza de que terei um monte de coisas para limpar no meu código.

😏 👍

Então, como a ideia é simplificar o uso do redux, posso propor 2 momentos:

  1. Adicione a função incorporada a literalmente expect(mapStateToProps(state)).toEqual(mapStateToProps(state)) . Apenas para encorajar as pessoas a criar um código melhor. Nunca vi testes como este, mas _not-very-pure_ mapStateToProps é um problema de redux.

  2. Considere a adoção de algo como memoize-state . É como o Immer.js para seletores. O ponto principal - o cliente pode simplesmente escrever mapStateToProps ou seletor no formato que preferir e fazer com que seja memorizado. Ele poderia até mesmo resolver esse problema de nova seleção com "Compartilhando Seletores com Acessórios em Instâncias de Múltiplos Componentes" sem perder memoização "comum" entre as instâncias. Basta memorizar duas vezes as coisas

  1. Eu vejo o que você quer dizer em termos de recomendação de seletores puros, mas um seletor idempotente impuro ainda poderia passar no teste. Eu gosto mais da segunda sugestão.
  2. Isso parece legal, então apenas envolvíamos os seletores da mesma forma que envolvíamos os redutores para immer, certo?

Ainda assim, como discutimos acima, isso é mais uma coisa react-redux do que algo que estaria no pacote inicial que é agnóstico para React.

Isso é muito legal!

No entanto, tenho um pedido / feedback; Eu preferiria se Immer não fosse usado implicitamente.

Immer é ótimo . Tornou-se um dos meus utilitários favoritos. Mas, mesmo quando o uso explicitamente ( produce(baseState, draftState => ... ), fico preocupado quando outras pessoas que não estão familiarizadas com ele visualizam meu código e não percebem que só posso fazer essas coisas mutantes por causa dos superpoderes do Immer.

Da forma como a API está agora, posso imaginar os novatos não percebendo que o estado de redux deve ser imutável. Eu acho que esse mal-entendido iria aborrecê-los quando tentassem usar o Redux sem este kit inicial.

Vejo que createNextState já é uma exportação, então por que não encorajar os usuários a usá-lo explicitamente:

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

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

(desculpe se eu não entendi como createNextState deve ser usado!

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

Da forma como a API está agora, posso imaginar os novatos não percebendo que o estado de redux deve ser imutável. Eu acho que esse mal-entendido iria aborrecê-los quando tentassem usar o Redux sem este kit inicial.

Em minha opinião, devemos recomendar não usar Redux diretamente em favor deste pacote quando estiver completo por causa de https://github.com/reactjs/redux/issues/2858. Basicamente, queremos alertar ou proteger os usuários de todas as mutações por padrão, mas não podemos fazer isso facilmente no núcleo sem quebrar as coisas, então devemos recomendar o uso do núcleo, exceto em casos extremos onde o kit inicial não é suficiente. Isso é semelhante a como o React recomenda o CRA e o Redux recomenda o react-redux ao usar o React.

Vejo que createNextState já é uma exportação, então por que não encorajar os usuários a usá-lo explicitamente:

Não é uma má ideia, mas acho que somos mais a favor de estar implícitos aqui, especialmente porque não estamos gerando código-fonte e a adição de immer é compatível com as versões anteriores.

Vejo muitas pessoas recomendando o uso de libs como immer.js , que na minha humilde opinião consiste em desviar involuntariamente a motivação de aprender e respeitar os store requisitos.

Todos nós sabemos que a loja não pode sofrer mutação, portanto, eu prefiro ter um mecanismo de validação onde ele verifica a instância newState contra ( === ) a previousState e se for a mesma instância, lance um erro.

Desta forma, todos seriam obrigados a aprender as regras e requisitos de store .

PS: Eu realmente entendo o benefício de immer e não tenho absolutamente nada contra isso, mas estamos chegando a um momento em que as pessoas estão finalmente entendendo o conceito, isso geraria uma grande fonte de confusão e, tecnicamente, se fizermos o benchmark, não faremos nada além de adicionar uma camada extra de complexidade apenas para liberar a biblioteca.

Sugestões pessoais:

logger , devTools e Thunk devem ser adicionados como padrão de Starter , o resto eu acredito que seja mais uma escolha pessoal.

Todos nós sabemos que o armazenamento não pode ser modificado, portanto, eu prefiro ter um mecanismo de validação onde ele verifica a instância newState contra (===) o previousState e se é a mesma instância emite um erro.

Há casos em que, dependendo da ação, você não gostaria que o estado mudasse, então você retornaria a mesma instância de armazenamento para economizar memória e evitar qualquer falso positivo. Mesmo se contornarmos esse problema, parece que o Redux não quer um validador no núcleo e eu acho que o Immer é uma proteção adequada para isso pessoalmente. Eu concordo que é meio que frustrar o propósito de aprender Redux até certo ponto, mas eu vejo tantos desenvolvedores aprendendo Redux que não querem aprender PF puro ou não estão cientes disso.

se fizermos o benchmark, não faremos nada além de adicionar uma camada extra de complexidade apenas para liberar a biblioteca.

Pelo que eu sei, a maneira como o Immer é implementado, o Proxy só tem sobrecarga de desempenho se estiver realmente mutado, portanto, redutores de atualização imutáveis ​​típicos não deveriam ter sobrecarga de desempenho. Acho que esse é um equilíbrio correto.

O logger, devTools e Thunk devem ser adicionados como padrão do Starter, o resto eu acredito que é mais uma escolha pessoal.

Existem algumas outras coisas que eu gostaria de considerar a remoção (embora eu pessoalmente não veja uma grande vantagem para o criador de logs sobre as ferramentas de desenvolvedor que compensa sua sobrecarga de desempenho), consulte https://github.com/markerikson/ redux-starter-kit / issues / 19. No entanto, não sou contra adicionar mais coisas se elas forem compatíveis com o nosso uso atual de Immer e Thunk.

Há casos em que, dependendo da ação, você não gostaria que o estado mudasse, então você retornaria a mesma instância de armazenamento para economizar memória e evitar qualquer falso positivo. Mesmo se contornarmos esse problema, parece que o Redux não quer um validador no núcleo e eu acho que o Immer é uma proteção adequada para isso pessoalmente. Eu concordo que é meio que frustrar o propósito de aprender Redux até certo ponto, mas eu vejo tantos desenvolvedores aprendendo Redux que não querem aprender PF puro ou não estão cientes disso.

@nickmccurdy Eu entendo totalmente o seu ponto de vista, e concordo que não devemos ter uma obstrução de aprendizagem devido a alguns conceitos de PF, Mutação e etc ... Mas como um educador, eu acredito fortemente em não cobrir de açúcar o aprendiz por escondendo a complexidade deles. Enfim, é só uma questão de gosto, sou um profissional em aprendizado e ousadia, e olhando para essa proposta, meus instintos de alguma forma me dizem que estaríamos avançando com aceitação, mas regredindo com os padrões. Apenas em observação, pense em todo o conteúdo da web agora ensinando Redux Standards e como ele finalmente está pegando.

Pelo que eu sei, a maneira como o Immer é implementado, o Proxy só tem sobrecarga de desempenho se estiver realmente mutado, portanto, redutores de atualização imutáveis ​​típicos não deveriam ter sobrecarga de desempenho. Acho que esse é um equilíbrio correto.

Quando quero dizer adicionar uma camada de complexidade, quero dizer que Immer nunca existiu e agora poderia estar, teríamos que oferecer suporte na biblioteca, testar, avaliar problemas de desempenho e, por último, mas não menos importante esta seção aqui, me deixa apreensivo:

Immer.js - Congelamento automático
O Immer congela automaticamente qualquer árvore de estado modificada com o uso de produtos. Isso protege contra modificações acidentais da árvore de estado fora de um produtor. Isso tem um impacto no desempenho, portanto, é recomendável desabilitar essa opção na produção. Está habilitado por padrão. Por padrão, ele é ativado durante o desenvolvimento local e desativado na produção. Use setAutoFreeze (true / false) para ativar ou desativar explicitamente esse recurso.

E de repente agora também precisamos oferecer suporte aos recursos adicionados em Development / Prod . É apenas uma boa quantidade de trabalho e preocupante para não haver muito o que fazer, mas, novamente, esta é apenas minha opinião pessoal.

@codedavinci : o objetivo desta biblioteca redux-starter-kit é adicionar ferramentas úteis e abstração ao processo "básico" de configuração da loja Redux. Além disso, observe que isso _não_ está indo para o núcleo do Redux em si, mas para uma biblioteca separada que gostaríamos de tornar uma parte "oficial" da organização Redux eventualmente.

Todo o seu código Redux existente funcionará. Todos os tutoriais existentes ainda funcionarão. Estamos apenas tentando adicionar uma abordagem mais simples com suporte oficial para configurar e usar o Redux.

@markerikson Eu entendo o objetivo de ter o kit inicial e estou totalmente Immer.js que muda o conceito, da biblioteca, as pessoas irão eventualmente aprender o starter-kit padrões e ignorar totalmente os conceitos básicos. Nenhuma mudança de loja é o lema, a Redux sempre vendeu, faz parte da marca.

PS: Eu entendo perfeitamente que Immer.js não muda nada, mas ajuda você a não fazer isso. Estou apenas falando sobre os padrões sintaticamente permitidos, como push , splice ...

Talvez seja eu mesmo resistindo a mudanças :)

@codedavinci : sim, eu entendo o ponto das preocupações. Ainda assim, uma das reclamações comuns sobre Redux é a dor de escrever código de atualização imutável adequado, e Immer é simplesmente a melhor biblioteca que já vi para simplificar essas atualizações.

@markerikson , eu realmente fiz algumas pesquisas sobre immer e percebi que é muito leve, simples e eficiente. Estou realmente vendido :).

Em qual repositório você está elaborando? Essa:

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

Sim, é isso.

@nickmccurdy tem um monte de PRs esperando para discussão e fusão, principalmente em torno de ferramentas, mas também alguma discussão sobre como queremos focar o projeto a longo prazo. Preciso dar uma olhada neles, mas estive ocupado com outras coisas nas últimas semanas (incluindo a palestra que darei amanhã).

Grande progresso @nickmccurdy & @markerikson 👍 Adoro a simplicidade e eficácia disso. @nickmccurdy notou que você é muito ativo no projeto, adoraria conversar com você sobre algumas ideias. Avise-me se estiver pronto para isso! :)

Claro, obrigado, provavelmente é melhor começar uma discussão aberta sobre um novo problema, mas você pode entrar em contato comigo diretamente por

1 para dividir combineReducers . Usei-o por mais tempo e porque, se fosse, não pensei muito sobre como minha loja funcionava.

Atualmente, gosto de configurar minha função de redutor ao longo das linhas 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,
  };
}

O que é algo que combineReducers realmente não me deixa fazer.

@ abradley2 : não estamos planejando remover combineReducers do núcleo Redux, se é isso que você está perguntando. Mas sim, sempre dissemos que combineReducers é um utilitário para o caso de uso mais comum e que você é incentivado a escrever uma lógica de redutor customizada para sua própria situação.

Temos o nome do pacote redux-starter-kit e o repo foi movido para a organização em https://github.com/reduxjs/redux-starter-kit . Vou fechar este tópico. Qualquer outra discussão pode acontecer nesse repo.

Além disso, estou começando a trabalhar na adição de verificações de mutação e serializabilidade por padrão.

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

ilearnio picture ilearnio  ·  3Comentários

olalonde picture olalonde  ·  3Comentários

captbaritone picture captbaritone  ·  3Comentários

mickeyreiss-visor picture mickeyreiss-visor  ·  3Comentários

vraa picture vraa  ·  3Comentários