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

React中this.state初始化遇空值,改用setState触发重复渲染的解决方法

问题解决:Next.js _app组件state初始化异常与重复渲染问题

一、constructor中state初始化无效的原因及修复

1. 修复事件绑定错误

你的componentWillUnmount方法中移除事件监听时,未通过this访问类方法,导致运行报错,可能间接引发state异常。修改如下:

componentWillUnmount(){
  if (typeof window !== 'undefined') { // 避免服务端执行window相关代码报错
    window.removeEventListener('resize', this.handleResize, false);
    window.removeEventListener('online', this.handleOnlineChange, false);
    window.removeEventListener('offline', this.handleOnlineChange, false);
  }
}

2. 改用类属性初始化state

在Next.js的SSR场景下,改用类属性初始化state可避免部分初始化阶段的兼容问题:

export default class MyApp extends App {
  // 类属性初始化state,自动兼容服务端/客户端
  state = {
    store: createStore(Mystore, composeWithDevTools(applyMiddleware(thunk))),
    onLine: typeof window !== 'undefined' ? window.navigator.onLine : null,
    Loginstatus: null,
    mobile: typeof window !== 'undefined' ? window.innerWidth < 700 : null,
    loading: typeof window !== 'undefined' ? window.innerHeight < 175 : true
  };

  constructor(props){
    super(props);
    // 此处不再赋值state
  }

  // ... 其他方法保持不变
}

二、减少不必要的重渲染

1. 合并初始化状态的setState调用

在checkLog方法中,仅更新需要异步获取的Loginstatus,其余状态已在初始化时完成设置,避免重复更新触发重渲染:

async checkLog()  {
  try {
    // 无需用Promise.resolve包裹,直接await异步方法
    const value = await AuthControl();
    this.setState({
      Loginstatus: value.data
    });
  } catch (err) {
    this.setState({
      Loginstatus: err
    });
  }
}

2. 给resize事件添加防抖处理

resize事件会频繁触发,通过防抖函数限制setState的调用频率:

// 封装防抖函数
debounce = (func, delay = 200) => {
  let timeoutId;
  return (...args) => {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => func.apply(this, args), delay);
  };
};

componentDidMount(){
  if (typeof window !== 'undefined') {
    window.addEventListener('online', this.handleOnlineChange, false);
    window.addEventListener('offline', this.handleOnlineChange, false);
    // 使用防抖后的resize处理函数
    const debouncedResize = this.debounce(this.handleResize);
    window.addEventListener('resize', debouncedResize, false);
    // 缓存防抖函数,用于卸载时移除监听
    this.debouncedResize = debouncedResize;
    this.checkLog();
  }
}

componentWillUnmount(){
  if (typeof window !== 'undefined') {
    window.removeEventListener('resize', this.debouncedResize, false);
    window.removeEventListener('online', this.handleOnlineChange, false);
    window.removeEventListener('offline', this.handleOnlineChange, false);
  }
}

3. 优化加载判断逻辑

原判断条件过于严格(比如离线时会一直显示加载),调整为仅在必要状态未就绪时显示加载:

render() {
  const { Component, pageProps } = this.props;

  // 仅在组件未就绪、加载中或登录状态未获取时显示加载
  if (!Component || !pageProps || this.state.loading || this.state.Loginstatus === null) {
    return( 
      <>
        <Head>
          <title>Loading</title>
          <meta name="description" content="Generated by Imtaki" />
          <link rel="icon" href="/favicon.ico" />
        </Head>
        <MyLoading/>
      </>
    )
  }

  const {Loginstatus, mobile, store} = this.state;

  return( 
    <Provider store={store}>
      <Head>
        <title>Imtaki</title>
        <meta name="description" content="Generated by Imtaki" />
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <Header logstatus={Loginstatus} winWidth={mobile}/>
      <Component logstatus={Loginstatus} winWidth={mobile} {...pageProps} />
      <Footer logstatus={Loginstatus} mobile={mobile} loc={"body"}/>
    </Provider>  
  )
}

三、Next.js中store与状态的最佳实践

如果希望进一步优化,可以在getInitialProps中提前创建store并获取登录状态,减少客户端的异步请求和重渲染:

static async getInitialProps({ Component, ctx }) {
  // 创建store,服务端每个请求独立创建,避免状态污染
  const allEnhancers = compose(
    composeWithDevTools(applyMiddleware(thunk))
  );
  const store = createStore(Mystore, allEnhancers);

  let Loginstatus = null;
  try {
    if (ctx.req) {
      // 服务端登录验证逻辑(比如从cookie中获取登录状态)
    } else {
      // 客户端执行登录验证
      const value = await AuthControl();
      Loginstatus = value.data;
    }
  } catch (err) {
    Loginstatus = err;
  }

  // 获取页面组件的props
  const pageProps = Component.getInitialProps ? await Component.getInitialProps(ctx) : {};

  return { pageProps, store, Loginstatus };
}

constructor(props){
  super(props);
  const { store, Loginstatus } = props;
  this.state = {
    store,
    onLine: typeof window !== 'undefined' ? window.navigator.onLine : null,
    Loginstatus,
    mobile: typeof window !== 'undefined' ? window.innerWidth < 700 : null,
    loading: typeof window !== 'undefined' ? window.innerHeight < 175 : true
  };
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 23:10:59