简体   繁体   English

在 redux-saga 应用程序中实现加载指示器的最佳方法是什么?

[英]What is the best way to implement Loading indicator in redux-saga app?

I'm developing app with (redux + redux-saga + typescript + typesafe-actions + ducks)我正在使用(redux + redux-saga + typescript + typesafe-actions +ducks)开发应用程序

I'm considering how to implement loading indicator during api call.我正在考虑如何在 api 调用期间实现加载指示器。

this is my structure这是我的结构

  state
    ducks
      common
        actions.ts
        reducers.ts
        sagas.ts
        selectors.ts
      group
        same as common/
      user
        same as common/

common/actions共同/行动

export const beginLoading = () => action(CommonActionTypes.BEGIN_LOADING);
export const endLoading = () => action(CommonActionTypes.END_LOADING);

group/sagas团体/传奇

export function* handleFetchGroup() {
  try {
    const { group } = yield call(
      Api.fetchGroup
    );
    yield put(addGroup(group));
  } catch (err) {
    console.error(err);
  }
}

user/sagas用户/传奇

export function* handleFetchUsers(action: addGroup) {
  try {
    yield take(ADD_GROUP);
    const users = yield call(
      Api.fetchUsers,
      action.payload.id
    );
    yield put(addUsers(users));
  } catch (err) {
    console.error(err);
  }
}

At first, I tried this.起初,我尝试了这个。

group/sagas团体/传奇

export function* handleFetchGroup() {
  try {
    yield put(beginLoading()); // added
    const { group } = yield call(
      Api.fetchGroup
    );
    for(const group of groups) {
        yield put(addGroup(group));
    }
    yield put(endLoading()); // added
  } catch (err) {
    yield put(endLoading());
    console.error(err);
  }
}

in this case, the loading indicator shows only during fetching group data.在这种情况下,加载指示器仅在获取组数据期间显示。

so I tried this.所以我试过这个。

export function* handleFetchGroup() {
  try {
    yield put(beginLoading()); 
    const { groups } = yield call(
      Api.fetchGroups
    );
    for(const group of groups) {
        yield put(addGroup(group));
    }
  } catch (err) {
    yield put(endLoading());
    console.error(err);
  }
}

user/sagas用户/传奇

export function* handleFetchUsers(action: addGroup) {
  try {
    yield take(ADD_GROUP);
    const users = yield call(
      Api.fetchUsers,
      action.payload.id
    );
    yield put(addUsers(users));
    yield put(endLoading()); // added
  } catch (err) {
    console.error(err);
    yield put(endLoading());
  }
}

in this case,the loading indicator disappeared when the first fetchUsers finished.在这种情况下,加载指示器在第一个 fetchUsers 完成时消失。

Finally I tried this.最后我尝试了这个。

export function* handleFetchGroup() {
  try {
    yield put(beginLoading());
    const { groups } = yield call(
      Api.fetchGroups
    );
    for(const group of groups) { 
        const users = yield call(Api.fetchUsers, group.id); // add
        yield put(addUsers(users));
    }
    yield put(endLoading());
  } catch (err) {
    yield put(endLoading());
    console.error(err);
  }
}

But in this case, group saga depends on user entity.但在这种情况下,group saga 取决于用户实体。 So I want to avoid this, but I didn't come up with it.所以我想避免这种情况,但我没有想出它。

Do you have any solution??你有什么解决办法吗??

I suggest to have isLoading property in user state and group state.我建议在用户状态和组状态下使用isLoading属性。 When action beginLoading for group is emitted (I assume, that this action will trigger handleFetchGroup ), set isLoading: true in group reducer.当为 group 发出 action beginLoading (我假设这个 action 将触发handleFetchGroup ),在 group reducer 中设置isLoading: true When group loading is finished, set isLoading: false in group reducer.组加载完成后,在组减速器中设置isLoading: false

Exactly the same logic implement for user.为用户实现完全相同的逻辑。 So isLoading which exist in user reducer will be set in response to beginLoading for user and so on.因此,存在于用户减速器中的isLoading将被设置以响应用户的beginLoading等等。

In component, which will display loading indicator have isLoading from group and isLoading from user and show loading indicator whenever either of two is true.在组分,其将显示负载指示器已经isLoading从组和isLoading从用户和显示负载指示每当以下两种是真实的。

For example (not tested, use as hint)例如(未测试,用作提示)

const LoadingIndicator: FC<{ user: UserState, group: GroupState }> = ({group, user}) => (
    group.isLoading || user.isLoading ? <div>Loading...</div> : null
}

export default connect(state => ({ user: state.user, group: state.group }), {})(LoadingIndicator)

I also see that you're triggering handleFetchUsers in response to ADD_GROUP .我还看到您正在触发handleFetchUsers以响应ADD_GROUP This also better to decouple.这也更好地解耦。 You may consider creating additional saga (for example loadAll ) which will trigger user load in response to group load finish.您可以考虑创建额外的 saga(例如loadAll ),它将触发用户加载以响应组加载完成。

For example (not tested)例如(未测试)

function *loadAll() {
    yield put(BEGIN_GROUP_LOAD)
    yield takeEvery(GROUP_LOAD_FINISHED, function*(action) => {
        yield handleFetchUsers(action)
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM