MST

星途 面试题库

面试题:React 中如何在生命周期方法里进行数据加载以避免重复请求

假设你正在开发一个 React 应用,在组件中需要从 API 获取数据。请描述如何在合适的生命周期方法里进行数据加载,并且阐述怎样防止在不必要的时候(比如组件重新渲染但数据未发生变化时)重复发起相同的数据请求。
26.6万 热度难度
前端开发React

知识考点

AI 面试

面试题答案

一键面试
  1. 在 React 类组件中使用生命周期方法加载数据
    • componentDidMount
      • 这是 React 类组件挂载后调用的生命周期方法。在这个方法里发起 API 请求是很常见的做法。例如:
import React, { Component } from'react';

class MyComponent extends Component {
    constructor(props) {
        super(props);
        this.state = {
            data: null
        };
    }
    componentDidMount() {
        fetch('your - api - url')
          .then(response => response.json())
          .then(data => this.setState({ data }));
    }
    render() {
        const { data } = this.state;
        return (
            <div>
                {data? <p>{JSON.stringify(data)}</p> : <p>Loading...</p>}
            </div>
        );
    }
}

export default MyComponent;
  • componentDidUpdate
    • 此方法在组件更新后调用。如果要根据 props 的变化来重新获取数据,可以在这里进行判断和请求。例如:
import React, { Component } from'react';

class MyComponent extends Component {
    constructor(props) {
        super(props);
        this.state = {
            data: null
        };
    }
    componentDidMount() {
        this.fetchData();
    }
    componentDidUpdate(prevProps) {
        if (prevProps.someProp!== this.props.someProp) {
            this.fetchData();
        }
    }
    fetchData() {
        fetch('your - api - url')
          .then(response => response.json())
          .then(data => this.setState({ data }));
    }
    render() {
        const { data } = this.state;
        return (
            <div>
                {data? <p>{JSON.stringify(data)}</p> : <p>Loading...</p>}
            </div>
        );
    }
}

export default MyComponent;
  1. 防止不必要的重复请求
    • 使用状态标记
      • 在发起请求前,设置一个状态标记,例如 isLoading。如果已经在加载数据,或者数据已经存在且没有触发重新请求的条件(如 props 变化),则不再发起新的请求。
import React, { Component } from'react';

class MyComponent extends Component {
    constructor(props) {
        super(props);
        this.state = {
            data: null,
            isLoading: false
        };
    }
    componentDidMount() {
        if (!this.state.isLoading &&!this.state.data) {
            this.setState({ isLoading: true });
            fetch('your - api - url')
              .then(response => response.json())
              .then(data => {
                    this.setState({ data, isLoading: false });
                });
        }
    }
    componentDidUpdate(prevProps) {
        if (prevProps.someProp!== this.props.someProp &&!this.state.isLoading &&!this.state.data) {
            this.setState({ isLoading: true });
            fetch('your - api - url')
              .then(response => response.json())
              .then(data => {
                    this.setState({ data, isLoading: false });
                });
        }
    }
    render() {
        const { data, isLoading } = this.state;
        return (
            <div>
                {isLoading? <p>Loading...</p> : (data? <p>{JSON.stringify(data)}</p> : <p>Not loaded yet</p>)}
            </div>
        );
    }
}

export default MyComponent;
  • 使用缓存
    • 可以创建一个全局的缓存对象,在请求数据前先检查缓存中是否已经有需要的数据。例如:
const dataCache = {};
import React, { Component } from'react';

class MyComponent extends Component {
    constructor(props) {
        super(props);
        this.state = {
            data: null
        };
    }
    componentDidMount() {
        if (!dataCache['your - api - url']) {
            fetch('your - api - url')
              .then(response => response.json())
              .then(data => {
                    dataCache['your - api - url'] = data;
                    this.setState({ data });
                });
        } else {
            this.setState({ data: dataCache['your - api - url'] });
        }
    }
    render() {
        const { data } = this.state;
        return (
            <div>
                {data? <p>{JSON.stringify(data)}</p> : <p>Loading...</p>}
            </div>
        );
    }
}

export default MyComponent;
  • 使用 React.memoshouldComponentUpdate
    • React.memo:对于函数组件,可以使用 React.memo 来包裹组件,它会对 props 进行浅比较。如果 props 没有变化,组件不会重新渲染,也就不会触发数据请求逻辑(前提是数据请求逻辑在 useEffect 依赖数组设置正确的情况下)。例如:
import React, { useEffect, useState } from'react';

const MyComponent = React.memo((props) => {
    const [data, setData] = useState(null);
    useEffect(() => {
        fetch('your - api - url')
          .then(response => response.json())
          .then(data => setData(data));
    }, []);
    return (
        <div>
            {data? <p>{JSON.stringify(data)}</p> : <p>Loading...</p>}
        </div>
    );
});

export default MyComponent;
 - **`shouldComponentUpdate`**:在类组件中,可以重写 `shouldComponentUpdate` 方法,通过比较当前和之前的 props 或 state 来决定是否允许组件更新。如果返回 `false`,组件不会更新,也就不会重复发起请求(前提是请求逻辑在 `componentDidUpdate` 等合适的生命周期方法中)。例如:
import React, { Component } from'react';

class MyComponent extends Component {
    constructor(props) {
        super(props);
        this.state = {
            data: null
        };
    }
    shouldComponentUpdate(nextProps, nextState) {
        // 比较 props 和 state 判断是否需要更新
        if (nextProps.someProp === this.props.someProp && nextState.data === this.state.data) {
            return false;
        }
        return true;
    }
    componentDidMount() {
        this.fetchData();
    }
    componentDidUpdate() {
        this.fetchData();
    }
    fetchData() {
        fetch('your - api - url')
          .then(response => response.json())
          .then(data => this.setState({ data }));
    }
    render() {
        const { data } = this.state;
        return (
            <div>
                {data? <p>{JSON.stringify(data)}</p> : <p>Loading...</p>}
            </div>
        );
    }
}

export default MyComponent;