Dva: Modelo: como "esperar" por mais / grupo de saga colocar chamadas em vigor

Criado em 5 jul. 2017  ·  21Comentários  ·  Fonte: dvajs/dva

Ola pessoal,
Nos últimos dois dias, procurei uma maneira de chamar effectB, effectC do ModelB, ModelC dentro de effectA no modelA e esperar por eles . Eu li os problemas (# 134, # 325 e muitos mais), mas não tive sorte em encontrar uma solução.

Após o login do usuário, quero iniciar alguns modelos antes de mostrar o painel.

appModel

* modelsInit({}, { put }) {
   yield put({ type: 'loadingShow' });
   yield put({ type: 'activity/query' });
   yield put({ type: 'xyz.../query' });
   yield put({ type: 'loadingHide' });
},

activityModel

  namespace: 'activity',
  .
  .
  .
  effects: {
    * query({ payload }, { call, put }) {
      const response = yield call(activityService.query, parse(payload));
      ...
  },
  .
  .
  .

Como "put" é assíncrono, 'loadingHide' infelizmente é chamado antes de 'atividade / consulta' ser concluída.

Existe alguma solução elegante para este problema?

Obrigado por sua ajuda antecipadamente @sorrycc , @ helloyou2012 , @cycgit , @nikogu , @LeuisKen , @nihgwu , @zuiidea , @longzhaobi ou qualquer outra pessoa; o).

Comentários muito úteis

@vipcxj你 的 这种 方式 会 造成 大量 的 重复 逻辑 我 是 这种 方式 实现 的
`` `javascript
{
namespace: 'app1',
efeitos: {
* run (param, {select, put, call, take}) {
rendimento put ({tipo: 'loadingShow'});
rendimento put ({type: 'app2 / run'});
rendimento take ('app2 / runOk');
rendimento put ({type: 'app3 / run'});
rendimento take ('app3 / runOk');
rendimento put ({type: 'loadingHide'});
}
},
};
`` ``

`` `javascript
{
namespace: 'app2',
efeitos: {
* run (param, {select, put, call}) {
chamada de rendimento (...);
rendimento put ({tipo: 'runOk'});
}
},
};
`` ``

javascript { namespace: 'app3', effects: { * run(param, {select, put, call}) { yield call(...); yield put({type: 'runOk'}); } }, }; ```` 但都避免不了造成阻塞 <strong i="33">@sorrycc</strong> 是否有什么非阻塞的实现方式,我感觉可以从take入手 take 要是支持 `且` 的逻辑关系就可以实现非阻塞了 类似这种 javascript
{
namespace: 'app1',
efeitos: {
* run (param, {select, put, call, take}) {
rendimento put ({type: 'loadingShow'});
rendimento put ({type: 'app2 / run'});
rendimento put ({type: 'app3 / run'});
yield take ('app2 / runOk') && yield take ('app3 / runOk')
rendimento put ({type: 'loadingHide'});
}
},
};
`` ``

Todos 21 comentários

na verdade, a chamada aceita uma função que retorna uma promessa. efeito é um gerador de função. não o use como argumento de chamada. Basta colocar seu código assíncrono em uma função que retorna promist e usá-lo como o argumento de chamada em vigor.

Obrigado por responder @vipcxj.
Tentei fazer isso antes, mas tenho problemas com rendimento ou colocação.

Você pode fornecer um exemplo no meu contexto?

use put para despachar redutor, use call para chamar uma função que retorna uma promessa.

  • modelsInit ({payload}, {put, call}) {
    rendimento put ({tipo: 'loadingShow'});
    chamada de rendimento (activityService.query, parse (carga útil));
    rendimento put ({type: 'xyz ... / query'});
    rendimento put ({type: 'loadingHide'});
    },

Não quero chamar o serviço de atividade em appModel se já tiver o serviço definido em activityModel e toda a próxima lógica.
Além disso, não quero usar o retorno de chamada, especialmente se eu quiser usar cerca de 10+ x "yield put ({type: 'xyz ... / query'});"

Eu preciso ligar

yield put({ type: 'activity/query' });
yield put({ type: 'xyz.../query' });
yield put({ type: 'xyz2.../query' });
.
.
.

e então (depois de todos eles) definir o carregamento.

yield put({ type: 'loadingHide' });

(algo como assíncrono / aguardar)

Porque ... / query preencherá os dados no armazenamento, talvez eu possa verificar todos os estados necessários em meu componente e, se estiver preenchido, despachar a ação 'loadingHide'. Isso talvez seja um caminho a percorrer, mas ainda estou interessado em exemplificar como esperar por mais de um _ put _ sem callback.

É impossível, o rendimento não é mágico, ele depende da estrutura de co. Em co-estrutura, aceite uma função ou promessa thunk.

Interessante.
Obrigado pela sua paciência e tempo!

Eu estou errado. rendimento aceita gerador e efeito é um gerador. portanto, use call e dê call a um gerador de função, não a uma string. bem assim:
javascript const effect= function * effect({ payload }, { put, call, select }) { yield put ... yield call ... yield select ... ... } const model = { effects: { effect, anotherEffect: *(action, { put, call, select }) { const payloadForEffect = ... yield call(effect, { payload: payloadForEffect }, { put, call, select }); } } }

@vipcxj não é útil, use outra função de efeito ou não, não importa o resultado
no meu caso, eu quero obter uma taskList e salvá-la no modelo log e, no modelo other , obter o primeiro taskId como um parâmetro de url


log modelo:

    * getLogTaskList({ payload: { buildId } }, { call, update }) {
      console.log('2. before inner fetch');
      const { tasks: taskList } = yield call(LogServices.getLogTaskList, buildId);
      console.log('3. before inner update');
      yield update({ taskList });
      console.log('4. after inner update');
    },

other modelo:

    * jumpToLogTask({ payload: { buildId } }, {put, select }) {

        console.log('1. outer fetch');
        yield put('log/getLogTaskList', { buildId });
        console.log('5. outer select taskList');
        const taskList = yield select(state => state.log.taskList);

      // or use effect function
      // const effect = function*() {
      //   console.log('1. outer fetch');
      //   yield put('log/getLogTaskList', { buildId });
      //   console.log('5. outer select taskList');
      //   const taskList = yield select(state => state.log.taskList);
      // };
      // yield call(effect);

      if (taskList.length) {
        yield put(routerRedux.push(`/log/${taskList[0].id}`));
      }
    },

o resultado é sempre 1 5 2 3 4 , talvez a única solução seja o retorno de chamada
isso ainda será um problema na próxima versão principal? @sorrycc

@daskyrk usa chamada, não colocada. chame a função assíncrona, coloque para a ação.

@vipcxj Eu realmente usei call, defini a função effect e yield call(effect) no comentário, significa que é inútil, pois sem chamar a função effect 。 há algo que eu não entendi?

       const effect = function*() {
         console.log('1. outer fetch');
         yield put('log/getLogTaskList', { buildId }); //don't use put, use call, and don't use string as argument, use function generator.
         console.log('5. outer select taskList');
         const taskList = yield select(state => state.log.taskList);
       };

@vipcxj你 的 这种 方式 会 造成 大量 的 重复 逻辑 我 是 这种 方式 实现 的
`` `javascript
{
namespace: 'app1',
efeitos: {
* run (param, {select, put, call, take}) {
rendimento put ({tipo: 'loadingShow'});
rendimento put ({type: 'app2 / run'});
rendimento take ('app2 / runOk');
rendimento put ({type: 'app3 / run'});
rendimento take ('app3 / runOk');
rendimento put ({type: 'loadingHide'});
}
},
};
`` ``

`` `javascript
{
namespace: 'app2',
efeitos: {
* run (param, {select, put, call}) {
chamada de rendimento (...);
rendimento put ({tipo: 'runOk'});
}
},
};
`` ``

javascript { namespace: 'app3', effects: { * run(param, {select, put, call}) { yield call(...); yield put({type: 'runOk'}); } }, }; ```` 但都避免不了造成阻塞 <strong i="33">@sorrycc</strong> 是否有什么非阻塞的实现方式,我感觉可以从take入手 take 要是支持 `且` 的逻辑关系就可以实现非阻塞了 类似这种 javascript
{
namespace: 'app1',
efeitos: {
* run (param, {select, put, call, take}) {
rendimento put ({type: 'loadingShow'});
rendimento put ({type: 'app2 / run'});
rendimento put ({type: 'app3 / run'});
yield take ('app2 / runOk') && yield take ('app3 / runOk')
rendimento put ({type: 'loadingHide'});
}
},
};
`` ``

@vipcxj Eh ... Existe call o efeito de outro modelo sem importá-lo?

Assim como @jindada , @ 2 é semelhante neste aspecto .

@daskyrk é todo chinês de qualquer maneira, então não falarei a linguagem dos pássaros ~ Existem muitos métodos, mas você tem que encapsular você mesmo, e a premissa é que você pode obter o modelo principal, analisar a string de efeito e encontrar o efeito em a top model e, em seguida, pense Faça o que quiser ~ Mas não sei se eu crio um aplicativo, se o dva pode garantir que esse é o aplicativo que criei e não copiará outro em algum momento, ou se o dva é já fornecidos no modelo. Ir para outros métodos de modelo?

@vipcxj parece não estar lá ainda. . Mas eu nunca usei o método take. @Jindada você quer dizer usar put assincronamente para chamar o efeito em outros modelos, e então usar o bloco take synchronous para esperar que a ação no parâmetro seja executada. Eu me pergunto se entendi, direito?
E esta frase: 支持 且 的逻辑关系就可以实现非阻塞了 refere-se aos dois efeitos assíncronos de'app2 / run 'e'app3 / run' que podem ser executados ao mesmo tempo, e então use take para esperar pelo resultado de forma síncrona?

Hmm, o que eu quero de forma assíncrona é descer quando 'app2 / run' e 'app3 / run' são executados. O take of saga suporta apenas a lógica de . Vamos ansiosos para dva @ 2 juntos

soga, e pegar esse tipo de operação, aprendeu

@JonasJonny
Put.resolve () está bloqueado
por exemplo:
yield put.resolve({ type: 'user/fetchCurrent', IdDangVien, });

@mikelhpdatke Obrigado pela contribuição.
A pergunta estava conectada com DVA v1.xx
Não tenho certeza, mas acho que put.resolve está "habilitado" para v2.xx

De qualquer forma, put.resolve é definitivamente a solução na v2.

const response = yield put.resolve({
  type: 'nameOfEffect',
  payload: {...},
});

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