You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native中如何等待Redux dispatch完成后再执行导航?

问题:如何等待Redux Saga的dispatch完成后执行导航?

在React Native组件中定义了onPressItem函数,需要先通过Redux dispatch FormActionLoadFormData动作,完成后再调用pushScreenOnFormScreen跳转页面。尝试用async/await修饰但报错'await has no effect on the type of this expression';用useEffect则导致导航函数多次执行,引发导航栈重复ID的警告/错误。

相关代码

组件中的onPressItem函数:

const onPressItem = async (formData: any) => {
setFormData(formData);
dispatch(FormActionLoadFormData(formData));

pushScreenOnFormScreen({
componentId: Screens.FORM_FIELDS_SCREEN,
passProps: { formData: formData, formFields: formFields },
});
};

对应的Saga处理代码:

function* FormSagaLoadFormData({
                             payload,
                           }: FormTypeLoadFormData): 
 Generator<ReturnYield> {
 try {
  // Getting the auth token from store.
 const token: any = yield select(userSelectorAuthenticationToken);

// Here the payload is just the { id: 00, name: '', ... }.
// @ts-ignore
const id: number = payload ? (payload.id ? payload.id : -1) : -1;
const result: any = yield call(ApiGetFormByID, {token, id});

let form: any = null;
try {
  form = result.data.data.form;
} catch (err) {
  //
}

if (form) {
  yield put({
    type: FORM_ACTION.REDUCER.SAVE_FORM_DATA,
    payload: form,
  });
}
 } catch (error) {
  console.log('FormSagaLoadFormData error', error);
 }
 }

解决方案

方法1:将导航逻辑移至Saga中执行

既然使用Redux Saga管理异步流程,最直接的方式是在Saga完成数据加载和store更新后,直接触发导航操作,确保流程顺序。

修改Saga代码,在成功保存form数据后调用导航:

function* FormSagaLoadFormData({
  payload,
}: FormTypeLoadFormData & { formFields?: any }): Generator<ReturnYield> {
  try {
    const token: any = yield select(userSelectorAuthenticationToken);
    const id: number = payload ? (payload.id ? payload.id : -1) : -1;
    const result: any = yield call(ApiGetFormByID, {token, id});

    let form: any = null;
    try {
      form = result.data.data.form;
    } catch (err) {
      // 处理数据解析错误
    }

    if (form) {
      yield put({
        type: FORM_ACTION.REDUCER.SAVE_FORM_DATA,
        payload: form,
      });
      // 数据更新完成后执行导航
      pushScreenOnFormScreen({
        componentId: Screens.FORM_FIELDS_SCREEN,
        passProps: { formData: form, formFields: payload.formFields },
      });
    }
  } catch (error) {
    console.log('FormSagaLoadFormData error', error);
  }
}

同时修改组件中的onPressItem,将formFields传入action的payload:

const onPressItem = (formData: any) => {
  setFormData(formData);
  dispatch(FormActionLoadFormData({
    ...formData,
    formFields: formFields
  }));
};

方法2:封装返回Promise的dispatch函数

通过给action添加回调,让Saga在流程结束时触发回调,从而实现await等待。

首先在组件中封装自定义dispatch:

const dispatchWithPromise = (action) => {
  return new Promise((resolve) => {
    action.onSuccess = resolve;
    dispatch(action);
  });
};

修改Saga代码,接收并执行回调:

function* FormSagaLoadFormData({
  payload,
  onSuccess,
}: FormTypeLoadFormData & { onSuccess?: () => void }): Generator<ReturnYield> {
  try {
    const token: any = yield select(userSelectorAuthenticationToken);
    const id: number = payload ? (payload.id ? payload.id : -1) : -1;
    const result: any = yield call(ApiGetFormByID, {token, id});

    let form: any = null;
    try {
      form = result.data.data.form;
    } catch (err) {
      // 处理解析错误
    }

    if (form) {
      yield put({
        type: FORM_ACTION.REDUCER.SAVE_FORM_DATA,
        payload: form,
      });
    }
    // 流程结束后触发回调
    onSuccess?.();
  } catch (error) {
    console.log('FormSagaLoadFormData error', error);
    onSuccess?.(); // 错误场景也可触发,或改为reject
  }
}

最后修改组件的onPressItem:

const onPressItem = async (formData: any) => {
  setFormData(formData);
  await dispatchWithPromise(FormActionLoadFormData(formData));
  
  pushScreenOnFormScreen({
    componentId: Screens.FORM_FIELDS_SCREEN,
    passProps: { formData: formData, formFields: formFields },
  });
};

方法3:监听store状态变化,配合useRef控制导航执行

如果不想修改Saga,可以通过监听store中formData的更新,用useRef标记当前触发的操作,避免重复导航。

在组件中添加监听逻辑:

import { useSelector } from 'react-redux';
import { useRef, useEffect } from 'react';

// 获取store中保存的form数据
const storeFormData = useSelector(state => state.form.formData);
const isPendingNavigation = useRef(false);
const lastTriggeredFormId = useRef<number | null>(null);

const onPressItem = (formData: any) => {
  setFormData(formData);
  lastTriggeredFormId.current = formData.id;
  isPendingNavigation.current = true;
  dispatch(FormActionLoadFormData(formData));
};

// 监听store中formData的变化
useEffect(() => {
  if (isPendingNavigation.current && storeFormData?.id === lastTriggeredFormId.current) {
    pushScreenOnFormScreen({
      componentId: Screens.FORM_FIELDS_SCREEN,
      passProps: { formData: storeFormData, formFields: formFields },
    });
    // 重置标记,避免重复执行
    isPendingNavigation.current = false;
    lastTriggeredFormId.current = null;
  }
}, [storeFormData, formFields, pushScreenOnFormScreen]);

内容的提问来源于stack exchange,提问作者user3431310

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 15:33:12