React常见面试题详解

发布时间:2023-05-22

一、React 生命周期

1、生命周期简介 React 生命周期是指 React 组件从实例创建到销毁的整个过程。其中包含挂载、更新和卸载三个阶段。 2、生命周期分类 React 生命周期可以分为三类:Mounting, Updating, Unmounting。其中 Mounting 指组件加载到 DOM 上,Update 指组件数据改变引起的重新渲染,Unmounting 指组件卸载销毁时。 3、常用生命周期 componentDidMount():组件挂载时调用,可以进行 AJAX 请求和 DOM 操作等。 componentDidUpdate():组件更新时调用,可以进行更新操作。 componentWillUnmount():组件卸载时调用,可以进行一些清理操作。

二、React 的虚拟 DOM

1、什么是虚拟 DOM 虚拟 DOM 是简化版的 DOM,是 React 中组件状态改变后重新渲染组件的关键技术。虚拟 DOM 通过一系列的比较和更新操作,尽可能地减少与真实 DOM 的交互,从而提高页面渲染效率。 2、虚拟 DOM 的优点 (1)提高页面渲染效率,避免了每次修改都涉及到真实 DOM 的操作; (2)简化了操作,提升了开发效率; (3)实现了 diff 算法,可以最小化更新 DOM,从而提高了页面性能。

三、React 组件间通信

1、组件间通信方式 (1)props 静态方式:通过 props 把数据从父组件传递到子组件。 (2)context 跨级方式:通过 context 属性可以在组件树中直接传递数据,跨级传递更加便捷。 (3)自定义事件方式:通过自定义事件向祖先或子孙组件传递信息。 2、props 与 state 的区别 (1)props 是父组件向子组件传递的数据;state 是组件自己的状态数据。 (2)props 是只读的,不允许子组件修改;state 可以由组件自己修改,但需要通过 setState() 方法改变。

四、React 高阶组件(HOC)

1、高阶组件简介 高阶组件是指将一个组件作为参数,并返回一个新组件的函数。 2、高阶组件的作用 (1)代码复用:将多个组件公用的逻辑抽取成一个高阶组件,避免代码冗余; (2)扩展组件功能:将某个组件需要的功能通过高阶组件注入的方式进行扩展; (3)渲染劫持:在不修改组件本身的前提下对组件进行渲染控制。 3、高阶组件示例代码:

// HOC
const withLoginStatus = (WrappedComponent) => {
  return class extends React.Component {
    constructor(props) {
      super(props);
      this.state = { isLoggedIn: false };
    }
    componentDidMount() {
      this.setState({ isLoggedIn: true });
    }
    render() {
      const { isLoggedIn } = this.state;
      return <WrappedComponent isLoggedIn={isLoggedIn} {...this.props} />;
    }
  }
}
// 组件
const MyComponent = ({ isLoggedIn }) => (
  <p>{isLoggedIn ? '您已登录' : '请登录'}</p>
);
// 使用
const WrappedComponent = withLoginStatus(MyComponent);
ReactDOM.render(<WrappedComponent />, document.getElementById('app'));

五、React 的性能优化

1、虚拟 DOM 优化 (1)减少不必要的渲染:通过 shouldComponentUpdate() 方法来控制是否需要重新渲染组件。 (2)合理使用 React.Fragment:减少多余的 DOM 包裹标签。 (3)使用 key 属性:相同的 key 值可以减少虚拟 DOM 比对时的计算量。 2、其他性能优化 (1)使用 React 生产环境构建:生产环境构建时可以去除开发环境下的调试代码和警告信息。 (2)避免过量渲染:尽可能减少 DOM 操作次数。 (3)优化 JavaScript 代码:避免使用循环嵌套等性能开销大的操作。 代码示例:

class MyComponent extends React.Component {
  shouldComponentUpdate(nextProps, nextState) {
    if (this.props.text === nextProps.text && this.state.count === nextState.count) {
      return false;
    }
    return true;
  }
  render() {
    return (
      <React.Fragment>
        <span key="text">{this.props.text}</span>
        <button key="btn">{this.state.count}</button>
      </React.Fragment>
    );
  }
}

六、Redux 与 React 结合

1、Redux 基本用法 (1)Action:定义数据操作的类型。 (2)Reducer:定义数据操作,并返回操作后的新数据。 (3)Store:用于管理应用的 State。 2、Redux 与 React 结合示例代码:

// Action
const ADD_TODO = 'ADD_TODO';
const REMOVE_TODO = 'REMOVE_TODO';
// Action Creator
const addTodo = (text) => ({
  type: ADD_TODO,
  payload: {
    text,
  },
});
const removeTodo = (id) => ({
  type: REMOVE_TODO,
  payload: {
    id,
  },
});
// Reducer
const todos = (state = [], action) => {
  switch (action.type) {
    case ADD_TODO:
      return [...state, action.payload.text];
    case REMOVE_TODO:
      return state.filter((item, index) => index !== action.payload.id);
    default:
      return state;
  }
};
// Store
const store = createStore(todos);
// React 组件
const TodoList = ({ todos }) => (
  <ul>
    {todos.map((item, index) => (
      <li key={index}>{item}</li>
    ))}
  </ul>
);
class TodoApp extends React.Component {
  constructor(props) {
    super(props);
    this.state = { todos: store.getState() };
    this.handleAdd = this.handleAdd.bind(this);
    this.handleRemove = this.handleRemove.bind(this);
  }
  componentDidMount() {
    this.unsubscribe = store.subscribe(() => {
      this.setState({ todos: store.getState() });
    });
  }
  componentWillUnmount() {
    this.unsubscribe();
  }
  handleAdd() {
    const text = prompt('请输入待办事项');
    if (text) {
      store.dispatch(addTodo(text));
    }
  }
  handleRemove(index) {
    store.dispatch(removeTodo(index));
  }
  render() {
    const { todos } = this.state;
    return (
      <React.Fragment>
        <TodoList todos={todos} />
        <button onClick={this.handleAdd}>新增</button>
      </React.Fragment>
    );
  }
}
ReactDOM.render(<TodoApp />, document.getElementById('app'));