MST
星途 面试题库

面试题:复杂场景下 React 组件生命周期与数据加载的协同优化

在一个大型 React 应用中,存在多层嵌套组件,并且有多个组件需要从不同的 API 加载数据,这些数据之间还存在依赖关系。请设计一套完整的数据加载策略,结合 React 的生命周期方法,详细说明如何实现数据的高效加载、缓存以及如何处理组件卸载时可能出现的内存泄漏和未完成的异步请求等问题。
39.0万 热度难度
前端开发React

知识考点

AI 面试

面试题答案

一键面试

1. 数据加载策略

  • 分离数据加载逻辑:将每个 API 的数据加载逻辑封装在单独的函数中,便于管理和复用。例如,可以使用 async/await 或者 Promise 来处理异步请求。
  • 建立数据依赖关系图:分析各个组件所需数据之间的依赖关系,确定数据加载的先后顺序。

2. 结合 React 生命周期方法实现数据加载

  • componentDidMount:在组件挂载后触发数据加载。如果数据有依赖关系,先加载依赖的数据,然后再根据依赖数据加载其他数据。例如:
import React, { Component } from 'react';

class MyComponent extends Component {
  state = {
    data1: null,
    data2: null
  };

  async componentDidMount() {
    try {
      const response1 = await fetch('api-url-for-data1');
      const data1 = await response1.json();
      this.setState({ data1 });

      const response2 = await fetch(`api-url-for-data2?param=${data1.someKey}`);
      const data2 = await response2.json();
      this.setState({ data2 });
    } catch (error) {
      console.error('Error loading data:', error);
    }
  }

  render() {
    const { data1, data2 } = this.state;
    return (
      <div>
        {data1 && <p>Data1: {JSON.stringify(data1)}</p>}
        {data2 && <p>Data2: {JSON.stringify(data2)}</p>}
      </div>
    );
  }
}
  • componentDidUpdate:如果组件的 props 或者 state 发生变化,可能需要重新加载数据。可以通过比较 prevProps 和 nextProps,或者 prevState 和 nextState 来决定是否需要重新加载。例如:
componentDidUpdate(prevProps, prevState) {
  if (prevProps.someProp!== this.props.someProp) {
    this.fetchNewData();
  }
}

3. 数据缓存

  • 内存缓存:在组件内部或者应用全局维护一个缓存对象。例如,可以在组件的静态属性中定义缓存,每次加载数据前先检查缓存中是否有对应的数据。
class MyComponent extends Component {
  static cache = {};

  async componentDidMount() {
    if (MyComponent.cache['data1']) {
      this.setState({ data1: MyComponent.cache['data1'] });
    } else {
      const response = await fetch('api-url-for-data1');
      const data = await response.json();
      MyComponent.cache['data1'] = data;
      this.setState({ data1: data });
    }
  }
}
  • 持久化缓存:使用 localStorage 或者 sessionStorage 进行持久化缓存。在数据加载后,将数据存储到本地存储中,下次加载时先从本地存储读取。注意处理数据的过期问题,可以在存储数据时同时存储时间戳,判断数据是否过期。

4. 处理组件卸载时的问题

  • 内存泄漏:确保在组件卸载时清除所有与该组件相关的定时器、事件监听器等。例如,如果在组件中使用了 setInterval,在 componentWillUnmount 中清除它。
componentDidMount() {
  this.timer = setInterval(() => {
    // some code
  }, 1000);
}

componentWillUnmount() {
  clearInterval(this.timer);
}
  • 未完成的异步请求:可以使用 AbortController 来取消未完成的异步请求。在发起请求时创建 AbortController 实例,并在 componentWillUnmount 中调用 abort 方法。例如:
class MyComponent extends Component {
  constructor(props) {
    super(props);
    this.controller = new AbortController();
  }

  async componentDidMount() {
    try {
      const response = await fetch('api-url', { signal: this.controller.signal });
      const data = await response.json();
      this.setState({ data });
    } catch (error) {
      if (error.name === 'AbortError') {
        console.log('Request aborted');
      } else {
        console.error('Error loading data:', error);
      }
    }
  }

  componentWillUnmount() {
    this.controller.abort();
  }
}