在 React 样板容器中获取初始数据的正确方法

Proper Way in Fetching Initial Data in React Boilerplate Container

我是 React Boilerplate 的新手,正在使用容器和传奇来获取页面的初始数据。我在实现这个的时候遇到了两个问题。

UsersPage\index.js

// imported all sagas, etc

export function UsersPage({
  dispatch,
  usersPage,
  onGetUsers,
  onChangeSearch,
  onSetActive,
}) {

  useInjectReducer({ key: 'usersPage', reducer });
  useInjectSaga({ key: 'usersPage', saga });

  onGetUsers();

  return (...);
}

UsersPage.propTypes = {
  dispatch: PropTypes.func.isRequired,
  usersPage: PropTypes.object,
  onGetUsers: PropTypes.func,
  onChangeSearch: PropTypes.func,
  onSetActive: PropTypes.func,
};

const mapStateToProps = createStructuredSelector({
  usersPage: makeSelectUsersPage(),
});

function mapDispatchToProps(dispatch) {
  return {
    dispatch,
    onGetUsers: () => dispatch(getUsers()),
    onChangeSearch: evt => dispatch(changeSearch(evt.target.value)),
    onSetActive: active => dispatch(setActive(active)),
  };
}

const withConnect = connect(
  mapStateToProps,
  mapDispatchToProps,
);

export default compose(withConnect)(UsersPage);

UsersPage\actions.js

...
export function getUsers() {
  console.log('action getUsers');
  return {
    type: constants.GET_USERS,
  };
}
...

UsersPage\saga.js

export function* getUsers() {
  console.log('saga getUsers');
  try {
    const response = yield call(api.users.getAll);
    yield put(
      getUsersSuccess({
        users: response.data.data,
      }),
    );
  } catch (err) {
    const error = err.response.data.message;
    yield put(getUsersFail(error));
  }
}

export default function* usersPageSaga() {
  yield takeLatest(constants.GET_USERS, getUsers);
}

当我第一次加载页面时,控制台日志显示如下:

action getUsers
saga watcher

但是,当我导航到其他页面,然后转到此页面时:

action getUsers
saga worker getUsers

问题 1

似乎第一次加载时,saga watcher 的调用晚于操作 (getUsers)。因此,它在第一次加载时失败,但在随后的加载中,saga worker 被调用得很好。我如何确保 saga watcher 在操作之前首先被调用?

问题 2

因为操作 (getUsers) 在渲染内部,所以每次有更新时都会调用它。因此,当 getUsers return 并将新数据应用到 reducer 时,将再次调用渲染并再次调用操作 (getUsers),从而导致无限循环。我们应该做什么或将初始数据实际加载到容器中的正确方法是什么?

要解决第一个问题,请尝试使用 takeEvery 而不是 takeLatest:

export default function* usersPageSaga() {
  yield takeEvery(constants.GET_USERS, getUsers);
}

关于第二个问题,可以用useEffect hook加载初始数据:

useEffect(()=> {
  // load the data
}, [])