React 组件与生命周期 
1. 什么是有状态组件和无状态组件? 
答案:
- 有状态组件(Stateful Components): - 包含自身的state(状态)
- 通常是类组件,但使用useState Hook的函数组件也可以是有状态的
- 可以处理复杂的逻辑和数据操作
 
- 无状态组件(Stateless Components): - 不包含自身的state
- 通常是函数组件
- 主要用于展示UI,接收props并渲染
 
示例:
// 有状态组件
class StatefulComponent extends React.Component {
  state = { count: 0 };
  render() {
    return <div>{this.state.count}</div>;
  }
}
// 无状态组件
function StatelessComponent(props) {
  return <div>{props.count}</div>;
}2. React 组件的生命周期方法有哪些?它们的调用顺序是什么? 
答案:React 类组件的生命周期方法可以分为三个阶段:
- 挂载阶段: - constructor()
- static getDerivedStateFromProps()
- render()
- componentDidMount()
 
- 更新阶段: - static getDerivedStateFromProps()
- shouldComponentUpdate()
- render()
- getSnapshotBeforeUpdate()
- componentDidUpdate()
 
- 卸载阶段: - componentWillUnmount()
 
调用顺序就是上述列出的顺序。注意,在 React 16.3 之后,一些生命周期方法被标记为不安全(如 componentWillMount, componentWillReceiveProps, componentWillUpdate),应避免使用。
3. componentDidMount() 方法有什么用途? 
答案:componentDidMount() 方法在组件被挂载到 DOM 后立即调用。这个方法通常用于:
- 执行副作用操作,如设置订阅或定时器
- 发起网络请求获取数据
- 直接操作 DOM
示例:
class MyComponent extends React.Component {
  componentDidMount() {
    // 发起 API 请求
    fetch('https://api.example.com/data')
      .then(response => response.json())
      .then(data => this.setState({ data }));
    // 设置定时器
    this.timer = setInterval(() => {
      console.log('Timer ticking');
    }, 1000);
  }
  componentWillUnmount() {
    // 清除定时器
    clearInterval(this.timer);
  }
  render() {
    // 渲染逻辑
  }
}4. shouldComponentUpdate() 方法的作用是什么?如何优化性能? 
答案:shouldComponentUpdate() 方法允许我们手动决定是否要重新渲染组件。它在 props 或 state 发生变化时,在渲染前被调用。
作用:
- 性能优��:通过比较新旧 props 和 state,决定是否需要重新渲染
- 避免不必要的渲染
优化性能的方法:
- 实现浅比较:比较新旧 props 和 state 的值
- 使用 React.PureComponent:自动实现浅比较的 shouldComponentUpdate
- 使用 React.memo 高阶组件(用于函数组件)
示例:
class MyComponent extends React.Component {
  shouldComponentUpdate(nextProps, nextState) {
    // 只有当 title 改变时才重新渲染
    return this.props.title !== nextProps.title;
  }
  render() {
    return <div>{this.props.title}</div>;
  }
}
// 使用 React.memo
const MyFunctionComponent = React.memo(function MyFunctionComponent(props) {
  return <div>{props.title}</div>;
});5. 什么是错误边界(Error Boundaries)?如何实现? 
答案:错误边界是 React 组件,它可以捕获并打印发生在其子组件树任何位置的 JavaScript 错误,并且,它会渲染出备用 UI,而不是渲染那些崩溃了的子组件树。
实现错误边界:
- 定义 static getDerivedStateFromError() 或 componentDidCatch() 方法
- 使用 state 来控制是否应该显示错误 UI
示例:
class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }
  static getDerivedStateFromError(error) {
    return { hasError: true };
  }
  componentDidCatch(error, errorInfo) {
    console.log('Error:', error, errorInfo);
  }
  render() {
    if (this.state.hasError) {
      return <h1>Something went wrong.</h1>;
    }
    return this.props.children;
  }
}
// 使用
<ErrorBoundary>
  <MyComponent />
</ErrorBoundary>6. React 16.3 之后的生命周期变化是什么?为什么要进行这些变化? 
答案:React 16.3 之后的主要生命周期变化:
- 引入了新的生命周期方法: - getDerivedStateFromProps
- getSnapshotBeforeUpdate
 
- 废弃了一些生命周期方法(在 17.0 版本中彻底移除): - componentWillMount
- componentWillReceiveProps
- componentWillUpdate
 
这些变化的原因:
- 为即将到来的异步渲染做准备
- 避免开发者在即将被移除的生命周期方法中编写副作用代码
- 鼓励更好的编码实践,如将副作用移到 componentDidMount 中
新的生命周期方法使用示例:
class MyComponent extends React.Component {
  static getDerivedStateFromProps(props, state) {
    // 根据 props 更新 state
    return null;
  }
  getSnapshotBeforeUpdate(prevProps, prevState) {
    // 获取更新前的一些信息
    return null;
  }
  componentDidUpdate(prevProps, prevState, snapshot) {
    // 使用 getSnapshotBeforeUpdate 的返回值
  }
}7. 如何在函数组件中模拟生命周期方法? 
答案:在函数组件中,我们可以使用 React Hooks 来模拟生命周期方法:
- componentDidMount: 使用 useEffect 并传入空数组作为依赖
- componentDidUpdate: 使用 useEffect 并传入依赖数组
- componentWillUnmount: 在 useEffect 中返回一个清理函数
示例:
import React, { useState, useEffect } from 'react';
function MyComponent() {
  const [data, setData] = useState(null);
  useEffect(() => {
    // 模拟 componentDidMount
    fetchData();
    // 模拟 componentWillUnmount
    return () => {
      // 清理工作,如取消订阅
    };
  }, []); // 空数组表示只在挂载和卸载时运行
  useEffect(() => {
    // 模拟 componentDidUpdate
    console.log('data has changed:', data);
  }, [data]); // 当 data 变化时运行
  const fetchData = () => {
    // 获取数据的逻辑
  };
  return <div>{/* 组件内容 */}</div>;
}8. React 中的 render 方法作用是什么?它应该是纯函数吗? 
答案:render 方法是 class 组件中唯一必须实现的方法。它的作用是:
- 检查 this.props 和 this.state 的变化
- 返回以下类型之一: - React 元素(通常通过 JSX 创建)
- 数组或 fragments
- Portals
- 字符串或数值类型
- Boolean 或 null
 
render 方法应该是纯函数,这意味着:
- 不应该修改组件的 state
- 每次调用时,相同的输入(props 和 state)应该返回相同的输出
- 不应该直接与浏览器交互(应该在 componentDidMount 或其他生命周期方法中执行这些操作)
示例:
class MyComponent extends React.Component {
  render() {
    return (
      <div>
        <h1>{this.props.title}</h1>
        <p>{this.state.content}</p>
      </div>
    );
  }
}9. 什么是 React 中的受控组件和非受控组件? 
答案:
- 受控组件: - 表单数据由 React 组件控制
- 通过 props 接收当前值,并通过回调通知变化
 
- 非受控组件: - 表单数据由 DOM 本身处理
- 通常使用 ref 来获取表单数据
 
示例:
// 受控组件
function ControlledInput() {
  const [value, setValue] = useState('');
  return (
    <input
      value={value}
      onChange={(e) => setValue(e.target.value)}
    />
  );
}
// 非受控组件
function UncontrolledInput() {
  const inputRef = useRef(null);
  function handleSubmit() {
    console.log(inputRef.current.value);
  }
  return (
    <>
      <input ref={inputRef} />
      <button onClick={handleSubmit}>Submit</button>
    </>
  );
}10. 什么是高阶组件(HOC)?它们有什么用途? 
答案:高阶组件(HOC)是一个函数,它接受一个组件作为参数并返回一个新的组件。HOC 是 React 中复用组件逻辑的高级技术。
HOC 的主要用途:
- 代码复用
- 渲染劫持
- State 抽象和操作
- Props 操作
示例:
function withLogging(WrappedComponent) {
  return class extends React.Component {
    componentDidMount() {
      console.log('Component is mounted');
    }
    render() {
      return <WrappedComponent {...this.props} />;
    }
  };
}
// 使用
const EnhancedComponent = withLogging(MyComponent);高阶组件可以用来实现横切关注点,如日志记录、权限控制,而不需要修改原组件的代码。