Como otimizar pequenas atualizações nos objetos do componente aninhado no React + Redux?

Código de exemplo:https://github.com/d6u/example-redux-update-nested-props/blob/master/one-connect/index.js

Ver demonstração ao vivo:http://d6u.github.io/example-redux-update-nested-props/one-connect.html

Como otimizar pequenas atualizações para adereços do componente aninhado?

Eu tenho componentes acima, Repo e RepoList. Quero atualizar a tag do primeiro repo (Linha 14) Então eu enviei umUPDATE_TAG açao. Antes de implementarshouldComponentUpdate, o envio demora cerca de 200 ms, o que é esperado, pois estamos perdendo muito tempo<Repo/>s que não mudaram.

Depois de adicionadoshouldComponentUpdate, a expedição leva cerca de 30ms. Após a criação do React.js, as atualizações custam apenas cerca de 17ms. Isso é muito melhor, mas a exibição da linha do tempo no console do desenvolvedor do Chrome ainda indica um quadro irregular (mais de 16.6ms).

Imagine se tivermos muitas atualizações como essa ou<Repo/> é mais complicado que o atual, não conseguiremos manter 60fps.

Minha pergunta é: para atualizações tão pequenas nos acessórios de um componente aninhado, existe uma maneira mais eficiente e canônica de atualizar o conteúdo? Ainda posso usar o Redux?

Eu tenho uma solução substituindo todos ostags com um redutor interno observável. Algo como

// inside reducer when handling UPDATE_TAG action
// repos[0].tags of state is already replaced with a Rx.BehaviorSubject
get('repos[0].tags', state).onNext([{
  id: 213,
  text: 'Node.js'
}]);

Então, assino seus valores dentro do componente Repo usandohttps://github.com/jayphelps/react-observable-subscribe. Isso funcionou muito bem. Cada envio custa apenas 5ms, mesmo com a compilação de desenvolvimento do React.js. Mas sinto que isso é um anti-padrão no Redux.

Atualização 1

Eu segui a recomendação na resposta de Dan Abramov enormalizou meu estado ecomponentes de conexão atualizados

A nova forma de estado é:

{
    repoIds: ['1', '2', '3', ...],
    reposById: {
        '1': {...},
        '2': {...}
    }
}

Eu adicioneiconsole.time por aíReactDOM.render tempoa renderização inicial.

No entanto, o desempenho está pior do que antes (renderização inicial e atualização). (Fonte:https://github.com/d6u/example-redux-update-nested-props/blob/master/repo-connect/index.js, Demonstração ao vivo:http://d6u.github.io/example-redux-update-nested-props/repo-connect.html)

// With dev build
INITIAL: 520.208ms
DISPATCH: 40.782ms

// With prod build
INITIAL: 138.872ms
DISPATCH: 23.054ms

Eu acho que conectar em todos os<Repo/> tem muita sobrecarga.

Atualização 2

Com base na resposta atualizada de Dan, precisamos retornarconnectémapStateToProps argumentos retornam uma função. Você pode conferir a resposta de Dan. Eu também atualizeias demos.

Abaixo, o desempenho é muito melhor no meu computador. E por diversão, também adicionei o efeito colateral na abordagem de redutor que falei (fonte, demonstração) (sério, não use, é apenas para experimentos)

// in prod build (not average, very small sample)

// one connect at root
INITIAL: 83.789ms
DISPATCH: 17.332ms

// connect at every <Repo/>
INITIAL: 126.557ms
DISPATCH: 22.573ms

// connect at every <Repo/> with memorization
INITIAL: 125.115ms
DISPATCH: 9.784ms

// observables + side effect in reducers (don't use!)
INITIAL: 163.923ms
DISPATCH: 4.383ms
Atualização 3

Acabei de adicionarexemplo react-virtualized com base em "conecte-se a cada memorização"

INITIAL: 31.878ms
DISPATCH: 4.549ms

questionAnswers(1)

yourAnswerToTheQuestion