如何确保在导航到另一个页面之前完成减速器响应操作?

How do I make sure that reducer response action is done before navigating to another page?

我目前正在将 Redux Saga 与 React Native 结合使用,我对如何正确处理在我导航到另一个页面之前 reducer 操作未完成触发成功或失败操作的情况有疑问。在导航到另一个页面之前,我需要等到触发成功或失败操作,但它仍然可以导航。

我设置了我的代码,以便它在导航之前检查加载或错误状态,但导航仍然会发生。我认为这是因为 updateItems 是异步的,并且在响应返回之前处理代码执行得如此之快,例如如果我确实遇到错误,页面将导航离开而不是等待,以便我可以在页面上显示错误。

我认为这可能与我需要在我的减速器中添加的东西有关,但我不确定。

这是我点击的触发 reducer 调用的方法,导航一切正常。

updateItems = () => {
    const { code } = this.state;
    const { loading, error } = this.props;
    const id = this.props.navigation.state.params.id;

    this.props.updateItems({
      id: id,
      code: code,
    });

    if (!loading && !error) {
      this.props.navigation.navigate("newPage");
    }
  };

这是减速器本身:

const UPDATE_ITEMS_REQUEST = "UPDATE_ITEMS_REQUEST";
const UPDATE_ITEMS_SUCCESS = "UPDATE_ITEMS_SUCCESS";
const UPDATE_ITEMS_FAILURE = "UPDATE_ITEMS_FAILURE";

export default (itemsReducer = (
  state = {
    data: {
      items: {},
    },
    error: null,
    loading: false,
  },
  { type, payload },
) => {
  switch (type) {
    case UPDATE_ITEMS_REQUEST:
      return Object.assign({}, state, { loading: true, error: null });
    case UPDATE_ITEMS_FAILURE:
      return Object.assign({}, state, { loading: false, error: payload });
    case UPDATE_ITEMS_SUCCESS:
      return {
        loading: false,
        error: null,
        data: payload,
      };
    default:
      return state;
  }
});

export function updateItems(payload) {
  return { type: UPDATE_ITEMS_REQUEST, payload };
}

export function updateItemsFailure(payload) {
  return { type: UPDATE_ITEMS_FAILURE, payload };
}

export function updateItemsSuccess(payload) {
  return { type: UPDATE_ITEMS_SUCCESS, payload };
}


function* updateItemsSaga(payload) {
  const response = yield call(putItems, payload);
  if (response.ok) {
    yield put(updateItemsSuccess(payload));
  } else {
    yield put(
      updateItemsFailure("There has been an error"),
    );
  }
}

export function* watchUpdateItems() {
  yield takeLatest(UPDATE_ITEMS_REQUEST, updateItemsSaga);
}

// API
const putItems = async payload => {
  const res = await fetch(
    `${env.url}/updateItems`,
    {
      method: "PUT",
      headers: {
        Accept: "application/json",
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        id: payload.payload.id,
        code: payload.payload.code,
      }),
    },
  );

  if (!res.ok)
    return {
      status: res.status,
      ok: false,
    };

  const response = await res.json();
  response.status = res.status;
  response.ok = res.ok;
  return response;
};
  1. 您可以使用 react routers useHistory 将用户重定向到 redux 操作中的新路由 more info on how to route
  2. 您可以添加一个标志并将其设置为 true 作为响应

看来问题出在updateItems。它有一个具有两个属性 { loading, error } 的内部范围。因为这不是一个生成器函数,一旦这个函数开始执行,一个动作 updateItems 被触发(这很好),然后导航发生,因为函数检查 { loading, error } (这是false & null 相应地)。

解决方案可以使用 updateItemsSaga 中的导航部分,如下所示:

function* updateItemsSaga(payload) {
  const response = yield call(putItems, payload);
  if (response.ok) {
    yield put(updateItemsSuccess(payload));
    this.props.navigation.navigate("newPage");
  } else {
    yield put(
      updateItemsFailure("There has been an error"),
    );
  }
}

或者,您可以从 updateItems 中提取条件并在您的组件本身中使用它:

const OldPage = ({ loading, error }) => {

    if (loading) {
        return <div>Loading... </div>
    } else if(error) {
        return <ErrorPage status="404">;
    } else {
        return <NewPage>;
    }

};

两者都应该阻止导航发生,直到项目更新成功。希望对你有帮助