百度前端一面高频react面试题指南

本文详细介绍了React中的高阶组件、Render Props和Hooks的区别,强调了Hooks如何解决两者存在的问题。讨论了React事件机制,生命周期方法,包括挂载、更新、卸载和错误处理阶段的关键步骤。同时,文章涵盖了React的forwardRef和useImperativeHandle,以及React diff算法和虚拟DOM的概念。最后,探讨了setState的异步行为和React Router中Route和Redirect的区别,以及React Hooks带来的便利和最佳实践。
摘要由CSDN通过智能技术生成

React 高阶组件、Render props、hooks 有什么区别,为什么要不断迭代

这三者是目前react解决代码复用的主要方式:

  • 高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧。HOC 自身不是 React API 的一部分,它是一种基于 React 的组合特性而形成的设计模式。具体而言,高阶组件是参数为组件,返回值为新组件的函数。
  • render props是指一种在 React 组件之间使用一个值为函数的 prop 共享代码的简单技术,更具体的说,render prop 是一个用于告知组件需要渲染什么内容的函数 prop。
  • 通常,render props 和高阶组件只渲染一个子节点。让 Hook 来服务这个使用场景更加简单。这两种模式仍有用武之地,(例如,一个虚拟滚动条组件或许会有一个 renderltem 属性,或是一个可见的容器组件或许会有它自己的 DOM 结构)。但在大部分场景下,Hook 足够了,并且能够帮助减少嵌套。

(1)HOC 官方解释∶

高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧。HOC 自身不是 React API 的一部分,它是一种基于 React 的组合特性而形成的设计模式。

简言之,HOC是一种组件的设计模式,HOC接受一个组件和额外的参数(如果需要),返回一个新的组件。HOC 是纯函数,没有副作用。

// hoc的定义
function withSubscription(WrappedComponent, selectData) {
   
  return class extends React.Component {
   
    constructor(props) {
   
      super(props);
      this.state = {
   
        data: selectData(DataSource, props)
      };
    }
    // 一些通用的逻辑处理
    render() {
   
      // ... 并使用新数据渲染被包装的组件!
      return <WrappedComponent data={
   this.state.data} {
   ...this.props} />;
    }
  };

// 使用
const BlogPostWithSubscription = withSubscription(BlogPost,
  (DataSource, props) => DataSource.getBlogPost(props.id));

HOC的优缺点∶

  • 优点∶ 逻辑服用、不影响被包裹组件的内部逻辑。
  • 缺点∶ hoc传递给被包裹组件的props容易和被包裹后的组件重名,进而被覆盖

(2)Render props 官方解释∶

"render prop"是指一种在 React 组件之间使用一个值为函数的 prop 共享代码的简单技术

具有render prop 的组件接受一个返回React元素的函数,将render的渲染逻辑注入到组件内部。在这里,"render"的命名可以是任何其他有效的标识符。

// DataProvider组件内部的渲染逻辑如下
class DataProvider extends React.Components {
   
     state = {
   
    name: 'Tom'
  }

    render() {
   
    return (
        <div>
          <p>共享数据组件自己内部的渲染逻辑</p>
          {
    this.props.render(this.state) }      </div>
    );
  }
}

// 调用方式
<DataProvider render={
   data => (
  <h1>Hello {
   data.name}</h1>
)}/>


由此可以看到,render props的优缺点也很明显∶

  • 优点:数据共享、代码复用,将组件内的state作为props传递给调用者,将渲染逻辑交给调用者。
  • 缺点:无法在 return 语句外访问数据、嵌套写法不够优雅

(3)Hooks 官方解释∶

Hook是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。通过自定义hook,可以复用代码逻辑。

// 自定义一个获取订阅数据的hook
function useSubscription() {
   
  const data = DataSource.getComments();
  return [data];
}
// 
function CommentList(props) {
   
  const {
   data} = props;
  const [subData] = useSubscription();
    ...
}
// 使用
<CommentList data='hello' />

以上可以看出,hook解决了hoc的prop覆盖的问题,同时使用的方式解决了render props的嵌套地狱的问题。hook的优点如下∶

  • 使用直观;
  • 解决hoc的prop 重名问题;
  • 解决render props 因共享数据 而出现嵌套地狱的问题;
  • 能在return之外使用数据的问题。

需要注意的是:hook只能在组件顶层使用,不可在分支语句中使用。、

React 事件机制

<div onClick={
   this.handleClick.bind(this)}>点我</div>

React并不是将click事件绑定到了div的真实DOM上,而是在document处监听了所有的事件,当事件发生并且冒泡到document处的时候,React将事件内容封装并交由真正的处理函数运行。这样的方式不仅仅减少了内存的消耗,还能在组件挂在销毁时统一订阅和移除事件。

除此之外,冒泡到document上的事件也不是原生的浏览器事件,而是由react自己实现的合成事件(SyntheticEvent)。因此如果不想要是事件冒泡的话应该调用event.preventDefault()方法,而不是调用event.stopProppagation()方法。 JSX 上写的事件并没有绑定在对应的真实 DOM 上,而是通过事件代理的方式,将所有的事件都统一绑定在了 document 上。这样的方式不仅减少了内存消耗,还能在组件挂载销毁时统一订阅和移除事件。

另外冒泡到 document 上的事件也不是原生浏览器事件,而是 React 自己实现的合成事件(SyntheticEvent)。因此我们如果不想要事件冒泡的话,调用 event.stopPropagation 是无效的,而应该调用 event.preventDefault

实现合成事件的目的如下:

  • 合成事件首先抹平了浏览器之间的兼容问题,另外这是一个跨浏览器原生事件包装器,赋予了跨浏览器开发的能力;
  • 对于原生浏览器事件来说,浏览器会给监听器创建一个事件对象。如果你有很多的事件监听,那么就需要分配很多的事件对象,造成高额的内存分配问题。但是对于合成事件来说,有一个事件池专门来管理它们的创建和销毁,当事件需要被使用时,就会从池子中复用对象,事件回调结束后,就会销毁事件对象上的属性,从而便于下次复用事件对象。

React的生命周期有哪些?

React 通常将组件生命周期分为三个阶段:

  • 装载阶段(Mount),组件第一次在DOM树中被渲染的过程;
  • 更新过程(Update),组件状态发生变化,重新更新渲染的过程;
  • 卸载过程(Unmount),组件从DOM树中被移除的过程;
1)组件挂载阶段

挂载阶段组件被创建,然后组件实例插入到 DOM 中,完成组件的第一次渲染,该过程只会发生一次,在此阶段会依次调用以下这些方法:

  • constructor
  • getDerivedStateFromProps
  • render
  • componentDidMount
(1)constructor

组件的构造函数,第一个被执行,若没有显式定义它,会有一个默认的构造函数,但是若显式定义了构造函数,我们必须在构造函数中执行 super(props),否则无法在构造函数中拿到this。

如果不初始化 state 或不进行方法绑定,则不需要为 React 组件实现构造函数Constructor

constructor中通常只做两件事:

  • 初始化组件的 state
  • 给事件处理方法绑定 this
constructor(props) {
   
  super(props);
  // 不要在构造函数中调用 setState,可以直接给 state 设置初始值
  this.state = {
    counter: 0 }
  this.handleClick = this.handleClick.bind(this)
}

(2)getDerivedStateFromProps
static getDerivedStateFromProps(props, state)

这是个静态方法,所以不能在这个函数里使用 this,有两个参数 propsstate,分别指接收到的新参数和当前组件的 state 对象,这个函数会返回一个对象用来更新当前的 state 对象,如果不需要更新可以返回 null

该函数会在装载时,接收到新的 props 或者调用了 setStateforceUpdate 时被调用。如当接收到新的属性想修改 state ,就可以使用。

// 当 props.counter 变化时,赋值给 state 
class App extends React.Component {
   
  constructor(props) {
   
    super(props)
    this.state = {
   
      counter: 0
    }
  }
  static getDerivedStateFromProps(props, state) {
   
    if (props.counter !== state.counter) {
   
      return
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值