Dva: ゚フェクトをキャンセルする方法

䜜成日 2018幎06月08日  Â·  11コメント  Â·  ゜ヌス: dvajs/dva

問題を再珟するためのコヌド:(再珟可胜なコヌドたたは手順を提䟛しおください

シナリオプロゞェクトにモデルAずモデルBに察応する2぀のペヌゞAずBがある堎合、各ペヌゞにいく぀かの非同期ネットワヌクリク゚ストがあり、これらは有効に開始され、返されたデヌタはレデュヌサヌを介しお珟圚のモデルに曞き蟌たれたす州。

ペヌゞAたたはペヌゞBを離れるずきは、次回再利甚するずきにダヌティデヌタにならないように、察応するモデルのデヌタをクリアしたいず思いたす。
componentWillUnmountメ゜ッドで、モデルに明確なレデュヌサヌを蚘述したした
dispatch{type$ {model.namespace} / clear}

期埅される動䜜:(期埅される通垞の効果

ナヌザヌがペヌゞAからペヌゞBに入るず、モデルAのデヌタがクリヌンアップされ、初期状態に埩元されたす。

実際の動䜜:(実際の効果

ナヌザヌがペヌゞAからペヌゞBに入るずき、非同期ネットワヌク芁求がペヌゞAで発生し、ネットワヌク芁求が完了する前にペヌゞBに入るず、ペヌゞAは最初にクリアレデュヌサヌを介しおモデルAデヌタをクリアしたすが、ネットワヌクが有効な堎合リク゚ストが完了するず、返されたデヌタはモデルAに曞き換えられるため、モデルAの前のビゞネスのデヌタがダヌティになりたす。

Aペヌゞを離れるずきに指定された効果をキャンセルしたり、名前空間内のすべおの効果をキャンセルしたりできたすか redux-sagaでキャンセルするのず同様

䜿甚されおいるパッケヌゞのバヌゞョン:(どのラむブラリのどのバヌゞョンに問題があるか

v2.2.3

最も参考になるコメント

@ wss1942ありがずう
このように、゚フェクトをキャンセルするこずができたす。ロヌドステヌタスを衚瀺するのは面倒です。dvaに付属のloading.effectsを盎接䜿甚しおロヌドステヌタスを衚瀺するこずはできたせん。倉曎するには、独自のコヌドを䜜成する必芁がありたす。
私はそれを倉曎し、完党なモデルコヌドを投皿したした

import { getProduct } from '@/services/Products';
import { isRespSucc, showErrorMsg } from '@/utils/utils';

const initState = {};

export default {
  namespace: 'product',

  state: initState,

  effects: {
    /**
      圚䞀䞪 Effects 之闎觊发䞀䞪竞赛race
      劂果task先结束竞赛结束。
      劂果task未结束时收到cancelrace effect 将自劚取消 task。
    */
    *cancelable({ task, payload }, { call, race, take }) {
      yield race({
        task: call(task, payload),
        cancel: take('cancel'),
      });
    },

    /**
      取消所有未完成的任务并执行数据枅理
    */
    *clear(_, { put }) {
      yield put.resolve({ type: 'cancel' });
      yield put({ type: 'clearState' });
    },

    *getProduct({ payload }, { call, put, cancelled }) {
      // eslint-disable-next-line
      yield put.resolve({ type: 'cancelable', task: getProductCancelable, payload });

      function* getProductCancelable(params) {
        try {
          // 调甚眑络请求
          const response = yield call(getProduct, params);
          // 返回结果刀断
          if (!isRespSucc(response)) {
            showErrorMsg(response);
            return;
          }
          // 取倌
          const { productName } = response.data;
          // 调甚reducer存倌
          yield put({
            type: 'saveState',
            payload: { productName },
          });
        } finally {
          if (yield cancelled()) {
            // TODO: 取消眑络请求
          }
        }
      }
    },
    *getCity(_, { call, put, cancelled }) {
      // eslint-disable-next-line
      yield put.resolve({ type: 'cancelable', task: getCityCancelable });

      function* getCityCancelable() {
        // TODO: 具䜓实现
      }
  },

  reducers: {
    saveState(state, { payload }) {
      const newState = { ...state, ...payload };
      return newState;
    },
    clearState() {
      return initState;
    },
  },
};


トランザクションcomponentWillUnmountを離れるずき、dispatch clearは珟圚のモデルのすべおの未完了の効果をキャンセルでき、getProductLoadingずgetCityLoadingも通垞どおり䜿甚できたす。

  componentWillMount() {
    const { dispatch } = this.props;
    dispatch({
      type: 'product/getProduct',
      payload: {
        productNumber: '123456',
      },
    });
    dispatch({
      type: 'product/getCity',
    });
  }

  componentWillUnmount() {
    const { dispatch } = this.props;
    dispatch({
      type: 'product/clear',
    });
  }

  function mapStateToProps(state) {
    return {
      getProductLoading: state.loading.effects['product/getProduct'],
      getCityLoading: state.loading.effects['product/getCity'],
    };
  }

党おのコメント11件

モデルのサブスクリプションのルヌティング倉曎を監芖し、ペヌゞが非AペヌゞAペヌゞを離れるたたはAペヌゞAペヌゞに入るの堎合、モデルAの状態を手動でクリアできたす。

回答ありがずうございたす。この方法を詊したした。状態自䜓をクリアしおも問題ありたせん。componentWillUnmountでクリアするこずも、サブスクリプションがルヌティングの倉曎を監芖するずきにクリアするこずもできたす。問題は、モヌダル状態をクリアした埌、非同期操䜜によっお返されるデヌタが゚フェクトで返されるこずです。それでもモヌダル状態に曞き換えられるため、前のビゞネスのデヌタがダヌティになりたす。
サブスクリプションのルヌティングの倉曎も監芖しおいたす。ペヌゞAを離れるずきは、unmodelを䜿甚しおモデルAをアンむンストヌルしたす。ペヌゞAに入り、モデルAを手動でロヌドするこずは無意味です。非同期通信が戻った堎合、モデルAが芋぀かっおいる限り、このモデルがビゞネスで最埌に䜿甚されたモデルであるか、新しくロヌドされたモデルであるかに関係なく、デヌタが曞き蟌たれたす。
したがっお、最良の方法は、モデルの状態をクリアし、珟圚の名前空間のすべおの効果をキャンセルするこずですが、呌び出すメ゜ッドが芋぀かりたせん。アドバむスを求める。

元のポスタヌの問題が発生したした。コンポヌネントがアンむンストヌルされたずきに未完成の効果をキャンセルしたかったのですが、方法がないこずがわかりたした。Dvaはこの皮のapi @ sorryccを提䟛しおいないようです。

効果をキャンセルしおサガを分離するこずは可胜ですか

@dlamonも同じ状況に遭遇し、ルヌトが切り替えられたずきにクリヌンアップしたいず考えおいたした。今解決策はありたすか

ルヌト切り替えが完了した埌、通信が戻らない可胜性があり、通信が戻った埌もダヌティデヌタがクリヌンアップされたモデルデヌタ領域に曞き戻されるため、 @ KyrieChenはルヌト切り替え䞭にクリヌンアップするこずは期埅されおいたせん。

私の珟圚のアプロヌチは、珟圚のトランザクションで䜿甚されるデヌタを栌玍するために䜿甚されるトランザクションを入力するたびにcomponentWillMountの堎合、珟圚のトランザクションに察応するモデルデヌタ領域にUUIDを持぀サブデヌタ領域を生成するこずです。UUIDが曞き蟌たれたすトランザクションが終了するずクリアされたすcomponentWillUnmount。以䞋のモデル構造ず同様です。
2018-11-07 7 25 31
クリアモデルの埌に通信が戻っおきた堎合、デヌタを曞き蟌むずきに、珟圚のレデュヌサヌによっお䜿甚されるUUIDは前のトランザクションで䜿甚されたUUIDであるため、ダヌティデヌタは前のトランザクションのデヌタ領域に曞き蟌たれ、次のトランザクションでは生成されたせん。圱響。

ただし、この方法も適切ではありたせん。1぀はロゞックの耇雑さを増し、2぀目は初期倀を取埗するにはnull倀の刀断を远加する必芁があるため、コヌドが耇雑になるこずです。私がやっおいるこずは䞻に金融システムのためなので、このような汚いデヌタが怖いので、この方法を遞びたす。
最善の方法はredux-sagaのキャンセル効果メカニズムに䌌おいるず思いたすが、dvaは珟圚それをサポヌトしおいないようです。
より良い解決策がある堎合は、@我

@dlamon私もそれに遭遇したした。私は自分でデモを曞きたした、そしお私は少し問題を感じたすhttps://codesandbox.io/s/yqwqpmvwvj

namespaceからproductsからmodelをeffectメ゜ッドでキャンセルしたす
dispatch({ type: 'products/@<strong i="10">@CANCEL_EFFECTS</strong>' });

このコヌドは

        yield sagaEffects.fork(function*() {
          yield sagaEffects.take(`${model.namespace}/@@CANCEL_EFFECTS`);
          yield sagaEffects.cancel(task);
        });

@ wss1942このメ゜ッドに返信しおいただきありがずうございたす。詊しおみたした。dispatch {type 'products / @ 796に䌌おいたす

@dlamon dvaは、効果をクリアするためのAPIを提䟛しおいないようです。ただし、モデルで定矩された効果で耇数のサガを曞き蟌むこずができたす。

 namespace: 'products',
 effects: {
  *start(){},
  *stop(){},
  watchLogin: [
      function* ({ take, put, call, cancel, fork, cancelled }) {
          yield take('start');
          const timerTask = yield fork(timer)
          const bgSyncTask = yield fork(bgSync)
          yield take('stop')
          yield cancel(bgSyncTask)
          yield cancel(timerTask)

        function* bgSync() {
          try {
            while (true) {
              const result = yield call(delay, 5 * 1000);
              yield put({ type: 'stop' })
            }
          } finally {
            if (yield cancelled())
              yield put({ type: 'log', payload: 'fetch🛑' })
          }
        }
        function* timer(time) {
          let i=0;
          while (true) {
            yield put({ type: 'log', payload: i++ })
            yield delay(1000)
          }
        }
      },
      { type: 'watcher' },
    ],
}

bgSyncは非同期タスクであり、 action startを䜿甚しおタスクを開始し、 actionstopを䜿甚しキャンセルできたす。これは、特定の効果をキャンセルするために実行できたす。
たた、非同期タスクがネットワヌクリク゚ストの堎合、ネットワヌクリク゚ストをキャンセルする操䜜も必芁になる堎合がありたす。たずえば、axios.CancelTokenを䜿甚しおaxiosをキャンセルできたす。

@ wss1942ありがずう
このように、゚フェクトをキャンセルするこずができたす。ロヌドステヌタスを衚瀺するのは面倒です。dvaに付属のloading.effectsを盎接䜿甚しおロヌドステヌタスを衚瀺するこずはできたせん。倉曎するには、独自のコヌドを䜜成する必芁がありたす。
私はそれを倉曎し、完党なモデルコヌドを投皿したした

import { getProduct } from '@/services/Products';
import { isRespSucc, showErrorMsg } from '@/utils/utils';

const initState = {};

export default {
  namespace: 'product',

  state: initState,

  effects: {
    /**
      圚䞀䞪 Effects 之闎觊发䞀䞪竞赛race
      劂果task先结束竞赛结束。
      劂果task未结束时收到cancelrace effect 将自劚取消 task。
    */
    *cancelable({ task, payload }, { call, race, take }) {
      yield race({
        task: call(task, payload),
        cancel: take('cancel'),
      });
    },

    /**
      取消所有未完成的任务并执行数据枅理
    */
    *clear(_, { put }) {
      yield put.resolve({ type: 'cancel' });
      yield put({ type: 'clearState' });
    },

    *getProduct({ payload }, { call, put, cancelled }) {
      // eslint-disable-next-line
      yield put.resolve({ type: 'cancelable', task: getProductCancelable, payload });

      function* getProductCancelable(params) {
        try {
          // 调甚眑络请求
          const response = yield call(getProduct, params);
          // 返回结果刀断
          if (!isRespSucc(response)) {
            showErrorMsg(response);
            return;
          }
          // 取倌
          const { productName } = response.data;
          // 调甚reducer存倌
          yield put({
            type: 'saveState',
            payload: { productName },
          });
        } finally {
          if (yield cancelled()) {
            // TODO: 取消眑络请求
          }
        }
      }
    },
    *getCity(_, { call, put, cancelled }) {
      // eslint-disable-next-line
      yield put.resolve({ type: 'cancelable', task: getCityCancelable });

      function* getCityCancelable() {
        // TODO: 具䜓实现
      }
  },

  reducers: {
    saveState(state, { payload }) {
      const newState = { ...state, ...payload };
      return newState;
    },
    clearState() {
      return initState;
    },
  },
};


トランザクションcomponentWillUnmountを離れるずき、dispatch clearは珟圚のモデルのすべおの未完了の効果をキャンセルでき、getProductLoadingずgetCityLoadingも通垞どおり䜿甚できたす。

  componentWillMount() {
    const { dispatch } = this.props;
    dispatch({
      type: 'product/getProduct',
      payload: {
        productNumber: '123456',
      },
    });
    dispatch({
      type: 'product/getCity',
    });
  }

  componentWillUnmount() {
    const { dispatch } = this.props;
    dispatch({
      type: 'product/clear',
    });
  }

  function mapStateToProps(state) {
    return {
      getProductLoading: state.loading.effects['product/getProduct'],
      getCityLoading: state.loading.effects['product/getCity'],
    };
  }
このペヌゞは圹に立ちたしたか
0 / 5 - 0 評䟡