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

如何避免React服务端渲染时浏览器重复发起相同异步请求

解决React SSR中重复发起异步请求的问题

我之前在做React SSR的时候也碰到过一模一样的问题——服务端已经通过fetchInitialData获取了数据,结果客户端挂载组件时又调用了一次接口,白白浪费请求资源。你说的检查数据是否存在确实可行,但确实有更显式、更优雅的方案,下面分享几个常用的解决思路:

1. 在Action Creator中加入条件判断(最推荐)

把“是否需要发起请求”的逻辑封装到Redux的action creator里,让它自己判断当前state中是否已有数据,避免重复请求。这样组件里不管是服务端的fetchInitialData还是客户端的componentDidMount,都可以放心调用,不用额外判断:

// 你的getUsers action creator修改成这样
export const getUsers = () => (dispatch, getState) => {
  // 先从state里拿已有数据
  const { users } = getState();
  // 如果数据已经存在,直接返回resolved的Promise,不发起请求
  if (users && users.length > 0) {
    return Promise.resolve();
  }
  // 否则正常发起异步请求
  return fetch('/api/users')
    .then(res => res.json())
    .then(data => {
      dispatch({ type: 'GET_USERS_SUCCESS', payload: data });
    })
    .catch(err => {
      dispatch({ type: 'GET_USERS_FAILURE', payload: err });
    });
};

这种方式把逻辑收敛到了action层,符合Redux的单一职责原则,组件代码也保持简洁,完全不用关心重复请求的问题。

2. 用高阶组件(HOC)封装数据获取逻辑

如果不想把判断逻辑放在action里,可以写一个专门处理SSR数据的HOC,把“是否在客户端重新获取数据”的逻辑抽离出来,让组件更干净:

const withSSRData = (Component, fetchInitialData) => {
  return class SSRDataWrapper extends React.Component {
    componentDidMount() {
      const { store } = this.props;
      // 根据你的state结构,检查对应数据是否存在
      const hasData = store.getState().users && store.getState().users.length > 0;
      if (!hasData) {
        fetchInitialData(store.dispatch);
      }
    }

    render() {
      return <Component {...this.props} />;
    }
  };
};

// 然后修改组件的导出
export default connect(
  state => ({ users: state.users }),
  dispatch => bindActionCreators({ getUsers }, dispatch)
)(withSSRData(Users, Users.fetchInitialData));

这个HOC可以复用在所有需要SSR数据的组件上,统一处理重复请求的问题,代码结构更清晰。

3. 利用服务端注入的初始状态标记

其实本质上和检查数据存在性类似,但可以更显式:服务端渲染完成后,会把Redux的初始状态注入到全局变量(比如window.__INITIAL_STATE__),客户端初始化store时会用这个状态。你可以在全局变量里加一个标记,记录哪些请求已经在服务端完成,比如:

// 服务端渲染时,在注入INITIAL_STATE的地方加个标记
const initialState = store.getState();
initialState._fetched = { users: true }; // 标记users数据已获取

// 客户端组件里
componentDidMount() {
  if (!window.__INITIAL_STATE__._fetched.users) {
    this.props.getUsers();
  }
}

不过这种方式需要维护额外的标记,不如前两种方案简洁,一般不推荐,但如果有特殊场景需要追踪哪些请求已执行,可以考虑。

为什么会出现重复请求?

简单说就是服务端和客户端是两个独立的执行环境:服务端通过fetchInitialData获取数据并渲染HTML,客户端接管页面后,组件挂载会触发componentDidMount,如果没有判断逻辑,就会再次调用接口。上面的方案都是通过不同方式让客户端“知道”数据已经存在,从而跳过重复请求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:07:34