Dva: Модель: Как "ждать" большего / группа саги ставит призывы в эффекты

Созданный на 5 июл. 2017  ·  21Комментарии  ·  Источник: dvajs/dva

Привет ребята,
Последние два дня я искал способ, как вызвать effectB, effectC из ModelB, ModelC внутри effectA в modelA и ждать их . Я читал проблемы (№ 134, № 325 и многие другие), но мне не удалось найти решение.

После входа в систему я хочу запустить несколько моделей, прежде чем показывать панель инструментов.

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));
      ...
  },
  .
  .
  .

Поскольку "put" является асинхронным, "loadingHide", к сожалению, вызывается до завершения "activity / query".

Есть ли изящное решение этой проблемы?

Заранее благодарим вас за помощь @sorrycc , @ helloyou2012 , @cycgit , @nikogu , @LeuisKen , @nihgwu , @zuiidea , @longzhaobi или кого-либо еще; o).

Самый полезный комментарий

@vipcxj你 的 这种 方式 会 造成 大量 的 重复 逻辑 我 是 这种 方式 实现 的
`` javascript
{
пространство имен: 'app1',
эффекты: {
* run (param, {выбрать, поставить, позвонить, взять}) {
yield put ({тип: 'loadingShow'});
yield put ({тип: 'app2 / run'});
yield take ('приложение2 / runOk');
yield put ({тип: 'app3 / run'});
yield take ('приложение3 / runOk');
yield put ({type: 'loadingHide'});
}
},
};
`` ''

`` javascript
{
пространство имен: 'app2',
эффекты: {
* run (param, {выбрать, поставить, позвонить}) {
yield call (...);
yield put ({тип: 'runOk'});
}
},
};
`` ''

javascript { namespace: 'app3', effects: { * run(param, {select, put, call}) { yield call(...); yield put({type: 'runOk'}); } }, }; ```` 但都避免不了造成阻塞 <strong i="33">@sorrycc</strong> 是否有什么非阻塞的实现方式,我感觉可以从take入手 take 要是支持 `且` 的逻辑关系就可以实现非阻塞了 类似这种 javascript
{
пространство имен: 'app1',
эффекты: {
* run (param, {выбрать, поставить, позвонить, взять}) {
yield put ({тип: 'loadingShow'});
yield put ({тип: 'app2 / run'});
yield put ({тип: 'app3 / run'});
yield take ('app2 / runOk') && yield take ('app3 / runOk')
yield put ({type: 'loadingHide'});
}
},
};
`` ''

Все 21 Комментарий

вызов фактически принимает функцию, которая возвращает обещание. эффект - генератор функций. не используйте его как аргумент вызова. Просто поместите свой асинхронный код в функцию, которая возвращает promist, и используйте его в качестве аргумента вызова в действительности.

Спасибо за ответ @vipcxj.
Я пытался сделать это раньше, но у меня проблема с yield или put.

Можете ли вы привести пример в моем контексте?

используйте put для отправки reducer, используйте call для вызова функции, которая возвращает обещание.

  • modelsInit ({payload}, {put, call}) {
    yield put ({тип: 'loadingShow'});
    yield call (activityService.query, parse (полезная нагрузка));
    yield put ({тип: 'xyz ... / запрос'});
    yield put ({type: 'loadingHide'});
    },

Я не хочу вызывать службу активности в appModel, если у меня есть служба, уже определенная в activityModel, и вся следующая логика.
Также я не хочу использовать обратный вызов, особенно если я хочу использовать около 10+ x "yield put ({type: 'xyz ... / query'});"

Мне нужно позвонить

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

а потом (после всех) установить загрузку.

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

(что-то вроде async / await)

Поскольку ... / query заполнит данные в хранилище, возможно, я смогу проверить все необходимые состояния в моем компоненте и, если он заполнен, отправить действие 'loadingHide'. Возможно, это выход, но мне все же интересно, как ждать более одного _ put _ без обратного вызова.

Это невозможно, yield - это не волшебство, это полагается на ко-фреймворк. В рамках co, yield принимает функцию thunk или обещание.

Интересно.
Спасибо за терпение и время!

Я не прав. yield accept генератор, а эффект - генератор. поэтому используйте вызов и вызовите генератор функций, а не строку. именно так:
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 это бесполезно, используйте другую функцию эффекта или нет, результат не имеет значения
в моем случае я хочу получить список задач и сохранить его в модели log , а затем в модели other получить первый taskId в качестве параметра URL


log модель:

    * 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 модель:

    * 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}`));
      }
    },

результат всегда 1 5 2 3 4 , возможно, единственное решение - обратный вызов
Будет ли это проблемой в следующей основной версии? @sorrycc

@daskyrk используйте call, а не put. вызовите асинхронную функцию, положите на действие.

@vipcxj Я действительно использовал call, я определил функцию effect и yield call(effect) в комментарии, я имею в виду, что это бесполезно, так как без вызова функции effect есть что-то, что я неправильно понял?

       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
{
пространство имен: 'app1',
эффекты: {
* run (param, {выбрать, поставить, позвонить, взять}) {
yield put ({тип: 'loadingShow'});
yield put ({тип: 'app2 / run'});
yield take ('приложение2 / runOk');
yield put ({тип: 'app3 / run'});
yield take ('приложение3 / runOk');
yield put ({type: 'loadingHide'});
}
},
};
`` ''

`` javascript
{
пространство имен: 'app2',
эффекты: {
* run (param, {выбрать, поставить, позвонить}) {
yield call (...);
yield put ({тип: 'runOk'});
}
},
};
`` ''

javascript { namespace: 'app3', effects: { * run(param, {select, put, call}) { yield call(...); yield put({type: 'runOk'}); } }, }; ```` 但都避免不了造成阻塞 <strong i="33">@sorrycc</strong> 是否有什么非阻塞的实现方式,我感觉可以从take入手 take 要是支持 `且` 的逻辑关系就可以实现非阻塞了 类似这种 javascript
{
пространство имен: 'app1',
эффекты: {
* run (param, {выбрать, поставить, позвонить, взять}) {
yield put ({тип: 'loadingShow'});
yield put ({тип: 'app2 / run'});
yield put ({тип: 'app3 / run'});
yield take ('app2 / runOk') && yield take ('app3 / runOk')
yield put ({type: 'loadingHide'});
}
},
};
`` ''

@vipcxj Эх ... Есть ли call эффекта другой модели без его импорта?

Подобно @jindada , @ 2 похожа в этом смысле.

@daskyrk в любом случае весь китайский, поэтому я не буду говорить на птичьем языке ~ Есть много методов, но вы должны инкапсулировать их самостоятельно, и предпосылка состоит в том, что вы можете получить топ-модель, проанализировать строку эффекта, найти эффект в топ-модель, а затем подумайте: делайте все, что хотите ~ Но я не знаю, создаю ли я приложение, могу ли dva гарантировать, что это приложение является приложением, которое я создал, и не будет копировать другое в какое-то время, или dva уже предусмотрено в модели. Перейти к другим методам модели?

@vipcxj, похоже, еще нет. . Но я никогда не использовал метод take. @Jindada вы хотите использовать асинхронно put для вызова эффекта в других моделях, а затем используйте синхронный блок take, чтобы дождаться выполнения действия в параметре. Интересно, понимаю ли я это, Правильно?
И это предложение: 支持 且 的逻辑关系就可以实现非阻塞了 относится к двум асинхронным эффектам: «app2 / run» и «app3 / run» могут выполняться одновременно, а затем использовать take для синхронного ожидания результата?

Хм, я хочу, чтобы асинхронно спускалось вниз, когда выполняются оба'app2 / run 'и'app3 / run'. Дубль саги поддерживает только логику . Давайте с нетерпением жду два @ 2 вместе

сога, и взяли такую ​​операцию, научились

@JonasJonny
Put.resolve () заблокирован
Например:
yield put.resolve({ type: 'user/fetchCurrent', IdDangVien, });

@mikelhpdatke Спасибо за ваш вклад.
Вопрос был связан с DVA v1.xx
Я не уверен, но думаю, что put.resolve "включен" с версии v2.xx

В любом случае, put.resolve определенно является решением в версии 2.

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

return response;
Была ли эта страница полезной?
0 / 5 - 0 рейтинги