MST
星途 面试题库

面试题:React 16.3+ 引入新的生命周期方法后,componentWillMount 有哪些替代方案及注意事项?

在React 16.3及以后版本,componentWillMount已被标记为不安全的生命周期方法。请说明为什么它变得不安全,以及在这种情况下,开发者应如何使用新的生命周期方法(如getDerivedStateFromProps和componentDidMount)来替代它原有的功能,同时避免常见误区。
45.0万 热度难度
前端开发React

知识考点

AI 面试

面试题答案

一键面试

为什么 componentWillMount 变得不安全

  1. 服务端渲染(SSR)问题:在服务端渲染时,componentWillMount 会在服务端和客户端各执行一次。这可能导致在服务端获取的数据和在客户端获取的数据不一致,从而产生“水合(hydration)”问题,即服务端渲染的内容与客户端渲染的内容不匹配。
  2. 异步渲染:React 16 引入了异步渲染机制(Fiber)。在异步渲染过程中,componentWillMount 可能会在渲染过程中被多次调用,这与它原本设计的只在挂载前调用一次的预期不符,导致不可预测的行为。

替代方案

  1. getDerivedStateFromProps
    • 功能getDerivedStateFromProps 是一个静态方法,在组件实例化后以及接受新的 props 时被调用。它的主要作用是根据新的 props 更新 state
    • 示例
class MyComponent extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            data: null
        };
    }
    static getDerivedStateFromProps(props, state) {
        if (props.newData && props.newData!== state.data) {
            return {
                data: props.newData
            };
        }
        return null;
    }
    render() {
        return <div>{this.state.data}</div>;
    }
}
  1. componentDidMount
    • 功能componentDidMount 在组件挂载到 DOM 后立即调用。它适用于需要操作 DOM、发起网络请求等副作用操作。
    • 示例
class MyComponent extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            data: null
        };
    }
    componentDidMount() {
        fetch('https://example.com/api/data')
          .then(response => response.json())
          .then(data => this.setState({ data }));
    }
    render() {
        return <div>{this.state.data}</div>;
    }
}

避免常见误区

  1. getDerivedStateFromProps 误区
    • 不要滥用:虽然 getDerivedStateFromProps 可以根据 props 更新 state,但过度使用会导致状态管理混乱。尽量只在 state 真正依赖 props 变化时使用。
    • 返回值:始终要返回一个对象来更新 state,或者返回 null 表示不需要更新 state。忘记返回或者返回错误类型会导致难以调试的错误。
  2. componentDidMount 误区
    • 避免阻塞渲染componentDidMount 中的操作应该是异步的,避免在其中执行长时间运行的同步任务,否则会阻塞主线程,影响用户体验。
    • 清理副作用:如果在 componentDidMount 中订阅了事件或创建了定时器等,需要在 componentWillUnmount 中进行清理,以防止内存泄漏。例如:
class MyComponent extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            count: 0
        };
    }
    componentDidMount() {
        this.timer = setInterval(() => {
            this.setState(prevState => ({
                count: prevState.count + 1
            }));
        }, 1000);
    }
    componentWillUnmount() {
        clearInterval(this.timer);
    }
    render() {
        return <div>{this.state.count}</div>;
    }
}