Não há conceitos novos, todos são antigos.
Por que dva?
Após um período de autoestudo ou treinamento, todos devem ser capazes de entender o conceito de redux e reconhecer que esse controle de fluxo de dados pode tornar a aplicação mais controlável e a lógica mais clara.
Mas geralmente há essa pergunta: há muitos conceitos e redutor, saga e ação são todos separados (sub-arquivos).
O problema com isso é:
E alguns outros:
E o dva é usado para resolver esses problemas.
dva é um pacote leve baseado na arquitetura de aplicação existente (redux + react-router + redux-saga, etc.), sem introduzir novos conceitos, e o código total é inferior a 100 linhas. (Inspirado por olmo e choo.)
dva é um framework, não uma biblioteca. Semelhante ao emberjs, ele irá dizer claramente como cada componente deve ser escrito, o que é mais controlável para a equipe. Além disso, dva encapsula todas as outras dependências, exceto react e react-dom, que são peerDependencies.
Na implementação do dva, tente não criar uma nova sintaxe, mas use a sintaxe da própria biblioteca de dependências, como a definição de roteador ou a sintaxe JSX de react-router (a configuração dinâmica é uma consideração de desempenho, que será suportada mais tarde).
O núcleo disso é fornecer o método app.model
, que é usado para encapsular redutor, initialState, ação e saga juntos, como:
app.model({
namespace: 'products',
state: {
list: [],
loading: false,
},
subscriptions: [
function(dispatch) {
dispatch({type: 'products/query'});
},
],
effects: {
['products/query']: function*() {
yield call(delay(800));
yield put({
type: 'products/query/success',
payload: ['ant-tool', 'roof'],
});
},
},
reducers: {
['products/query'](state) {
return { ...state, loading: true, };
},
['products/query/success'](state, { payload }) {
return { ...state, loading: false, list: payload };
},
},
});
Antes do dva, normalmente criamos sagas/products.js
, reducers/products.js
e actions/products.js
e depois alternamos entre esses arquivos.
Apresente as chaves desses modelos: (supondo que você já esteja familiarizado com a arquitetura de aplicativos do redux, redux-saga)
Consulte exemplos:
devtool
Suporte no nível da ferramenta de desenvolvimento?
Além da substituição a quente, que ainda não foi adaptada, outras como redux-devtool, css livereload, etc. são todas compatíveis.
Já está disponível para o ambiente de compilação?
Pode.
Inclui todos os recursos da arquitetura de aplicativos redux + redux-saga anterior?
sim.
Compatibilidade do navegador?
O IE8 não suporta porque o redux-saga é usado. (Consideraremos o suporte a thunks, promessas, observáveis, etc. na camada de efeitos de maneira estendida posteriormente)
Ser vivificado pelo redux é simplesmente gospel. É muito simples e elegante. Grande elogio! ! !
btw, eu acidentalmente vi um estrangeiro repostando no Twitter hoje, pensei que fosse escrito por um estrangeiro, mas não esperava que fosse um colega de classe do Alipay, 👍
Ansioso para a expansão dos efeitos
O ambiente de produção Alipay está usando essa arquitetura?
O @besteric dva acabou de sair e ainda não foi aplicado, mas a arquitetura do aplicativo por trás dele já é usada há algum tempo.
O redutor pode ser escrito assim:
const reducer = (state, { type, payload }) => {
switch (type) {
case 'products/query':
return { ...state, loading: true, };
case 'products/query/success':
return { ...state, loading: false, list: payload };
default
return state;
}
}
app.model({
reducer
})
Isso torna possível aplicar alguns métodos de ordem superior ao redutor.
Elogios, eu escrevi algumas demos e há apenas um problema, o modelo só pode ser usado
app.model(Model1);
app.model(Model2);
É este método para completar a combinação, na verdade, acho que o ideal é
app.model([Model1,Model2])
algum tipo de
É muito problemático passar despacho entre componentes, considere a seguinte solução
Não use bindActionCreators
?
O cenário específico do uso avançado do redutor @yesmeck é apenas redo/undo
?Não quero que o dva seja muito flexível e considerarei adicioná-lo por meio do complemento no futuro.
Usamos muito em nosso projeto. Por exemplo, vamos extrair as partes semelhantes de vários redutores em um método de alto nível para modificar o redutor original, e existem métodos de alto nível que permitem que o redutor redefina o estado quando a rota changes. , e este https://github.com/erikras/multireducer
@ Tinker404 Acho que seria mais claro declarar o modelo separadamente e seria mais fácil adicionar e excluir. Eu escreveria isso:
app.model(require('../models/a'));
app.model(require('../models/b'));
@JimmyLv pessoalmente prefere não usar actionCreator, mas apenas dispatch
.
@yesmeck ok, vou pensar sobre isso novamente.
Existem também métodos de ordem superior que permitem que o redutor redefina o estado quando a rota muda
Eu sinto que esse cenário é mais apropriado assinando as alterações de roteamento em subscriptions
e redefinindo o estado por meio de ação. Ou há alguma vantagem em usar o método de intensificador redutor?
Eu sinto que esse cenário é mais apropriado assinando as alterações de roteamento nas assinaturas e, em seguida, redefinindo o estado por meio de ação
Nesse caso, cada redutor que precisa ser resetado precisa escrever a lógica de reset. Se usarmos um método de alto nível, só precisamos fazer isso agora:
combineReducers({
products: composeReducers({ // composeReducers 的实现见下面
recycle(LOCATION_CHANGE, initialState), // recycle 用来在路由变化时重置状态
products
})
})
Outro cenário é a mesma lógica que estou falando em extrair diferentes redutores. Por exemplo, existe uma lista de produtos e uma lista de usuários, e seus redutores são assim:
// reducers/products.js
const reducer = (state, { type, action}) => {
switch (type) {
case 'products/FETCH_SUCCESS':
return {
...state,
loading: false,
list: payload
}
default:
return state
}
}
// reducers/users.js
const reducer = (state, { type, payload}) => {
switch (type) {
case 'users/FETCH_SUCCESS':
return {
...state,
loading: false,
list: payload
}
default:
return state
}
}
Aqui os dois redutores são quase os mesmos, então extraímos e escrevemos um redutor de lista:
const list = (actionType) => {
return (state, { type, payload }) => {
switch (type) {
case actionType:
return {
...state,
loading: false,
list: payload
}
break;
default:
return state
}
}
}
Em seguida, implementamos um composeReducers
para combinar esses 3 redutores:
function composeReducers(...reducers) {
return (state, action) => {
if (reducers.length === 0) {
return state
}
const last = reducers[reducers.length - 1]
const rest = reducers.slice(0, -1)
return rest.reduceRight((enhanced, reducer) => reducer(enhanced, action), last(state, action))
}
}
Dessa forma, o redutor para a lista de produtos e a lista de usuários se torna este:
// reducers/products.js
const reducer = (state, { type, payload}) => {
// 其他逻辑
}
export default composeReducer(reducer, list('products/FETCH_SUCCESS'))
// reducers/users.js
const reducer = (state, { type, payload}) => {
// 其他逻辑
}
export default composeReducer(reducer, list('users/FETCH_SUCCESS'))
list é apenas um exemplo, na verdade, existem muitos redutores no projeto que possuem a mesma lógica.
@yesmeck 👍, o papel do potenciador redutor já foi subestimado antes.
@sorrycc você pode dizer por quê? Chamado explicitamente com comparação dispatch
?
@ Tinker404 Acho que seria mais claro declarar o modelo separadamente e seria mais fácil adicionar e excluir. Eu escreveria isso:
app.model(require('../models/a'));
app.model(require('../models/b'));
Também sugiro um método que pode passar vários modelos ao mesmo tempo. Projetos grandes podem ter muitos modelos. Agora preciso (importar) todos eles e depois modelar cada modelo um por um, o que não é muito conveniente. Minha maneira atual da escrita é:
// models是个文件夹,有很多model
import models from './models';
models.forEach((m)=>{
app.model(m);
});
// models.js
const context = require.context('./', false, /\.js$/);
const keys = context.keys().filter(item => item !== './index.js');
const models = [];
for (let i = 0; i < keys.length; i++) {
models.push(context(keys[i]));
}
export default models;
É muito D.VA.
Encontrei o uso do componente antd form no user-dashboard. Lembro que não pode ser usado para componente puro. É possível agora?
@codering Não me lembro de haver restrições, problemas com antd podem ser solicitados em https://github.com/ant-design/ant-design/issues .
Olá, eu quero usar seu dva. Atualmente, eu uso a estrutura de diretórios gerada pelo scaffolding React Webpack Redux. Eu alterei o código com referência ao exemplo do painel de usuário no seu exemplo, mas não há nada após o início. Você pode ajudar me descobrir onde está? Algo deu errado, meu endereço do projeto: https://github.com/baiyulong/lenovo_parts
@baiyulong por que não fazê-lo diretamente com base na estrutura de diretórios do painel do usuário?
@sorrycc Estou usando a estrutura de diretórios do painel de usuário agora. Existe algum tratamento especial ou gravação para roteamento dva?
export default function({ history }) {
return (
<Router history={history}>
<IndexRoute component={HomePage} />
<Route path='/' component={HomePage}>
<Route path='/create' component={CreateOrder} />
</Route>
</Router>
)
}
Esta rota eu escrevi, HomePage pode, escrevi um link <Link to='/create'>Create</Link>
, não consigo ir para o componente CreateOrder depois de clicar nele
Não há uma maneira especial de escrever a rota de @baiyulong dva , tente:
@nikogu muito obrigado, ficarei bem depois de aninhar
Olá, o dva pode suportar carregamento a quente de modelos?
@kkkf1190 está considerando isso e irá apoiá-lo.
👍
Só queria dizer obrigado. . .
Sempre achei muito bom o andaime do vue-cli do vuejs. Depois de ler isso, meu pensamento mudou completamente.
Quadro muito maravilhoso! Faz um tempo que estou pesquisando. @sorrycc Quero fazer duas perguntas a Yunda:
@freemember007
@sorrycc Existe uma solução para suporte a redutores de ordem superior agora? Nosso projeto usa muitos redutores de alta ordem devido à reutilização
Suportado por @ancheel , pode ser global ou local, caso de uso de referência: https://github.com/dvajs/dva/blob/master/test/reducers-test.js
Depois que o estado do modelo é modificado, como modificá-lo novamente, esse problema sempre ocorre agora
antd.js:32924 Aviso: setState(...): Não é possível atualizar durante uma transição de estado existente (como em render
ou no construtor de outro componente). Os métodos de renderização devem ser uma função pura de props e state; constructor os efeitos colaterais são um antipadrão, mas podem ser movidos para componentWillMount
.
Muito emocionante, tente usá-lo no ambiente de produção, espero continuar otimizando e melhorando
nerfa isso!
Bom trabalho。Obrigado!!
@sorrycc Ansioso para oferecer suporte à renderização do lado do servidor!
Suportado por @mountainmoon , consulte https://github.com/sorrycc/dva-boilerplate-isomorphic .
Uma onda de rodas veio :+1:
Olá, acabei de entrar em contato com o aprendizado deste dva. Depois de ler o código por alguns dias, tenho algumas dúvidas em meu coração. Gostaria de perguntar:
Vi que seus demos são todos aplicativos de página única, mas todos são aplicativos de várias páginas em desenvolvimento. Gostaria de perguntar se o roteamento não é usado no desenvolvimento de aplicativos de várias páginas, como carregar componentes, talvez eu esteja perguntando a um idiota. É um pouco confuso, porque eu não uso roteamento, então o listener definido nos modelos não fica claro onde acionar:
history.listen( local => {
if(location.pathname === '/users') {
Despacho({
type:'querySuccess',
carga útil:{}
})
}
})
PS: Ao carregar dados no método querySuccess e usar export default connect(mapStateToProps)(Users); também é relatado um erro:
connect.js:41 Uncaught TypeError: não é possível chamar uma classe como uma função
Eu me sinto um idiota em um instante, não sei se posso incomodá-lo para me explicar, obrigado!
Por que dva? inglês, por favor
Não gosto muito dessa forma de escrever.
@codering você mencionou o uso de componentes de formulário antd no user-dashboard. Lembro que não pode ser usado para componentes puros. É possível agora?
Eu também encontrei mais.Se for um componente de função pura, a função getFieldDecorator não pode ser obtida através de props.form.getFieldDecorator.Se você usar extends para criar um componente, você pode obtê-lo.
Não sei se Deus tem solução @sorrycc
Você pode, por favor, lançar a mesma página em inglês? Não somos capazes de entender isso, e por que precisamos de dva.
Olá, se for um projeto grande, seu estado será muito grande e será muito trabalhoso para processar. Deveria ser dividido em vários modelos?
@yazhou-zyz eu tenho o mesmo problema que você:
Aviso: setState(...): Não é possível atualizar durante uma transição de estado existente (como dentro de render ou construtor de outro componente). Métodos de renderização devem ser uma função pura de props e state; os efeitos colaterais do construtor são um anti-padrão, mas pode ser movido para componentWillMount.
Gostaria de saber como você resolveu?
Aprender
continue estudando
dva é de grande valor de referência para projetos de construção.
bom trabalho~
Onde posso encontrar os documentos em inglês ??? Traduzir o tópico com mecanismos de tradução é problemático e o entendimento não é suficiente. Com o inglês, vocês podem alcançar o mundo. Mantenha o bom trabalho!! :foguete:
dva não é testado nas versões 0.47.X e React16.0.0 nativas do React
@vecold sempre foi capaz de usá-lo, dizendo que o código de convite ou mensagem de erro não pode ser usado
Existe uma chance de conseguirmos a tradução em inglês dos documentos?
Obrigado!
No código comercial, esse exemplo é comum. Uma atualização de estado local pode afetar todo o corpo. Muitos locais que não precisam ser renderizados novamente também são renderizados novamente, o que reduz muito o desempenho da página. Essa função pode ser adicionada para analisar automaticamente o estado do qual o redux connect depende para reduzir cálculos desnecessários de mapStateToProps e renderizar novamente 👍
muito bom
mas constrói toda a página quando espero construir uma única página
_tradução não oficial_
Redux é bom. Mas há muitos conceitos, redutores separados, sagas e ações (divididas em arquivos diferentes)
É um wrapper lite sobre o framework existente (redux + react-router + redux-saga ...). Nenhum novo conceito envolvido. < 100 linhas de código. (Inspirado por olmo e choo.)
É um framework, não uma biblioteca. Assim como o Ember.js, ele restringe a maneira como você escreve cada parte. É mais controlável para o trabalho em equipe. Dva encapsula todas as dependências exceto react e react-dom como peerDependencies
Sua implementação introduz novas sintaxes o menos possível. Ele reutiliza as dependências. Por exemplo, a definição do roteador é exatamente da mesma maneira que o JSX do roteador de reação.
A funcionalidade principal é app.model
. Ele encapsula o redutor, o initialState, a ação e a saga completamente.
app.model({
namespace: 'products',
state: {
list: [],
loading: false,
},
subscriptions: [
function(dispatch) {
dispatch({type: 'products/query'});
},
],
effects: {
['products/query']: function*() {
yield call(delay(800));
yield put({
type: 'products/query/success',
payload: ['ant-tool', 'roof'],
});
},
},
reducers: {
['products/query'](state) {
return { ...state, loading: true, };
},
['products/query/success'](state, { payload }) {
return { ...state, loading: false, list: payload };
},
},
});
Costumávamos criar sagas/products.js, reducers/products.js actions/products.js
e alternar entre eles.
ponto chave:
key
do reducer
em seu objeto rootReducer
initialState
de reducer
Veja exemplos
devtool
recarga a quenteEffects
suporta mais modelos saga
Suporte para ferramentas de desenvolvimento?
Compatível com redux-devtool, css livereload. Precisa de mais trabalho para recarga a quente
Bom para prod env?
certo
Incluindo todas as funcionalidades do redux + redux-saga?
sim
Compatibilidade de navegadores?
Sem IE8 devido ao redux-saga. (Mais tarde pode aplicar thunk, promessa, observável como extensões na camada de efeitos)
por favor semelhante
['products/query']: function*() {}
['products/query'](state) {}
Qual é a sintaxe? Os arrays podem ser usados como nomes de funções?
@clemTheDasher O nome da função pode ser uma chave computada ( NÃO array) em JavaScript. Referência mais detalhada às definições de Método |
var obj = {
property( parameters… ) {},
*generator( parameters… ) {},
async property( parameters… ) {},
async* generator( parameters… ) {},
// with computed keys:
[property]( parameters… ) {},
*[generator]( parameters… ) {},
async [property]( parameters… ) {},
// compare getter/setter syntax:
get property() {},
set property(value) {}
};
Relatórios de recém-chegados, venha aqui e continue trabalhando duro para aprender o conhecimento de front-end
@clemTheDasher Essa é a propriedade computada.
Por que o link https://github.com/dvajs/dva/tree/master/examples/count 404?
Aprender!
olhar para Deus
Graças a Deus, obrigado pelo código aberto
não estou autorizado a aprender com vocês!
Eu aprendi, obrigado por ter uma estrutura tão conveniente para nós usarmos
Os links de demonstração no github expiraram.
@sorrycc o dva suporta renderização no lado do servidor agora?
O redutor pode ser escrito assim:
const reducer = (state, { type, payload }) => { switch (type) { case 'products/query': return { ...state, loading: true, }; case 'products/query/success': return { ...state, loading: false, list: payload }; default return state; } } app.model({ reducer })
Isso torna possível aplicar alguns métodos de ordem superior ao redutor.
O estilo de escrita Redux é conciso, e apenas uma linha é necessária para modificar o estado, mas parece que várias linhas de código são escritas juntas através do açúcar sintático. Mas ainda preciso usar ...state
para entregar o status restante para a próxima parada, caso contrário o status ficará incompleto. Em outras palavras, durante a fase de redução, algum estado pode ser perdido se for escrito incorretamente.
De certa forma, a ideia do Vuex é mais fácil de ler e mais natural. Escreva algo assim (não exatamente).
const mutation = {
['products/query'](state) {
state.loading = true
},
['products/query/success'](state, payload) {
state.loading = false
state.list = payload
}
}
Em termos de código, eu só me importo com o estado que eu (sincronamente) modifico. O Vuex também deve envolver uma camada externa para entrega na próxima parada do estado. Possivelmente, algumas verificações defensivas (suposições) também são feitas antes da entrega, ou ganchos são colocados.
Pergunte-me se a página de exemplo do site oficial da dva não pode sair e relatar um erro, é uma atualização?
por favor semelhante
['products/query']: function*() {} ['products/query'](state) {}
Qual é a sintaxe? Os arrays podem ser usados como nomes de funções?
O ES6 permite que literais definam objetos, (expressão) como o nome da propriedade do objeto, ou seja, coloque a expressão entre colchetes.
Tal como
obj = {
['xxname']: 'what ever you defined',
['xxyy'](args) {
....
}
}
Existe uma dúvida, 'produtos/consulta' é usado para processar a chamada de redutores, e é associado ao namespace através de uma string, posteriormente, se o projeto se tornar maior, como centenas de métodos. Se meu namspace tiver que ser alterado. Para mudar uma centena de métodos?
@yesmeck 👍, o papel do potenciador redutor já foi subestimado antes.
Não sabe se há suporte aqui?
Comentários muito úteis
Ser vivificado pelo redux é simplesmente gospel. É muito simples e elegante. Grande elogio! ! !
btw, eu acidentalmente vi um estrangeiro repostando no Twitter hoje, pensei que fosse escrito por um estrangeiro, mas não esperava que fosse um colega de classe do Alipay, 👍