MST

星途 面试题库

面试题:React列表渲染结合条件展示时的性能优化

在一个大型React应用中,有一个包含大量数据项的列表,每个数据项根据其内部状态决定是否展示特定内容。由于数据量庞大,每次重新渲染都会导致性能问题。请描述你会采取哪些策略来优化列表渲染结合条件展示的性能,例如使用shouldComponentUpdate或React.memo等,并给出简单的代码示例说明如何应用这些策略。
45.6万 热度难度
前端开发React

知识考点

AI 面试

面试题答案

一键面试

1. 使用 React.memo

React.memo 是一个高阶组件,它可以对函数式组件进行浅比较,当 props 没有变化时,阻止组件重新渲染。

import React from 'react';

// 定义数据项组件
const Item = React.memo(({ data, shouldShow }) => {
    return shouldShow && <div>{data}</div>;
});

const BigList = () => {
    const largeData = Array.from({ length: 1000 }, (_, i) => `Item ${i}`);
    const [state, setState] = React.useState({});

    const handleToggle = (index) => {
        setState((prevState) => ({
          ...prevState,
            [index]:!prevState[index]
        }));
    };

    return (
        <div>
            {largeData.map((data, index) => (
                <div key={index}>
                    <button onClick={() => handleToggle(index)}>
                        Toggle {index}
                    </button>
                    <Item data={data} shouldShow={state[index] || false} />
                </div>
            ))}
        </div>
    );
};

export default BigList;

2. 使用 shouldComponentUpdate(类组件)

在类组件中,shouldComponentUpdate 方法允许我们手动控制组件是否应该重新渲染。

import React, { Component } from'react';

class Item extends Component {
    shouldComponentUpdate(nextProps) {
        return this.props.data!== nextProps.data || this.props.shouldShow!== nextProps.shouldShow;
    }

    render() {
        const { data, shouldShow } = this.props;
        return shouldShow && <div>{data}</div>;
    }
}

class BigList extends Component {
    constructor(props) {
        super(props);
        this.state = {};
        this.handleToggle = this.handleToggle.bind(this);
    }

    handleToggle(index) {
        this.setState((prevState) => ({
          ...prevState,
            [index]:!prevState[index]
        }));
    }

    render() {
        const largeData = Array.from({ length: 1000 }, (_, i) => `Item ${i}`);
        return (
            <div>
                {largeData.map((data, index) => (
                    <div key={index}>
                        <button onClick={() => this.handleToggle(index)}>
                            Toggle {index}
                        </button>
                        <Item data={data} shouldShow={this.state[index] || false} />
                    </div>
                ))}
            </div>
        );
    }
}

export default BigList;

3. 使用虚拟列表

对于超大数据量的列表,可以使用虚拟列表技术,例如 react - virtualizedreact - window

react - window 为例:

import React from'react';
import { FixedSizeList } from'react - window';

const Item = React.memo(({ index, data, shouldShow }) => {
    return shouldShow && <div>{data[index]}</div>;
});

const BigList = () => {
    const largeData = Array.from({ length: 10000 }, (_, i) => `Item ${i}`);
    const [state, setState] = React.useState({});

    const handleToggle = (index) => {
        setState((prevState) => ({
          ...prevState,
            [index]:!prevState[index]
        }));
    };

    const rowCount = largeData.length;
    const rowHeight = 35;

    return (
        <div>
            <FixedSizeList
                height={400}
                rowCount={rowCount}
                rowHeight={rowHeight}
                width={300}
            >
                {({ index }) => (
                    <div>
                        <button onClick={() => handleToggle(index)}>
                            Toggle {index}
                        </button>
                        <Item index={index} data={largeData} shouldShow={state[index] || false} />
                    </div>
                )}
            </FixedSizeList>
        </div>
    );
};

export default BigList;

4. 减少不必要的重新渲染范围

  • 确保 state 的更新粒度最小化,避免不必要地触发父组件重新渲染,进而影响子列表组件。
  • 使用 useCallbackuseMemo 来缓存函数和值,防止因为父组件重新渲染导致子组件依赖的函数或值变化而触发不必要的重新渲染。例如:
import React, { useCallback, useMemo } from'react';

const Item = React.memo(({ data, shouldShow }) => {
    return shouldShow && <div>{data}</div>;
});

const BigList = () => {
    const largeData = Array.from({ length: 1000 }, (_, i) => `Item ${i}`);
    const [state, setState] = React.useState({});

    const handleToggle = useCallback((index) => {
        setState((prevState) => ({
          ...prevState,
            [index]:!prevState[index]
        }));
    }, []);

    const listItems = useMemo(() => {
        return largeData.map((data, index) => (
            <div key={index}>
                <button onClick={() => handleToggle(index)}>
                    Toggle {index}
                </button>
                <Item data={data} shouldShow={state[index] || false} />
            </div>
        ));
    }, [largeData, state, handleToggle]);

    return (
        <div>
            {listItems}
        </div>
    );
};

export default BigList;