react的基础概念

react 常用知识

1、React 生命周期有以下不同的阶段:

Mounting(挂载)阶段:

constructor:组件实例化时被调用,用于初始化 state 和绑定方法。 static
getDerivedStateFromProps:在组件实例化以及每次接收新的 props 时被调用,用来根据新的 props 更新
state。 render:创建组件的虚拟 DOM 树并返回。
componentDidMount:组件第一次渲染完成后被调用,通常用于执行异步操作和订阅事件。

Updating(更新)阶段:

static getDerivedStateFromProps:接收到新的 props 时被调用,用来根据新的 props 更新
state。 shouldComponentUpdate:在组件更新之前被调用,用于确定是否需要进行组件的重新渲染。
render:重新渲染组件的虚拟 DOM 树并返回。 getSnapshotBeforeUpdate:在 render 之后、更新 DOM
之前被调用,用于获取更新前的 DOM 快照。 componentDidUpdate:DOM 更新完成后被调用,通常用于执行与 DOM
更新有关的操作。

Unmounting(卸载)阶段:

componentWillUnmount:组件被卸载之前被调用,通常用于执行一些清理操作,如取消订阅和清除计时器等。
此外还有一部分方法被称为错误处理(Error Handling)阶段:

捕获错误阶段

static getDerivedStateFromError:在后代组件抛出错误后被调用,用于渲染备用 UI。
componentDidCatch:在后代组件抛出错误后被调用,通常用于记录错误信息。

React 生命周期中的一些常用函数包括:

componentDidMount:在组件挂载后调用,通常用于执行异步操作、请求数据或订阅事件。
componentDidUpdate:在组件更新后调用,可以执行与 DOM 更新有关的操作,如更新某些元素的样式或重新计算布局。
componentWillUnmount:在组件将要卸载时调用,可以执行一些清理操作,如取消订阅或清除定时器。
render:用于渲染组件的虚拟 DOM 树,描述组件应该如何显示在页面上。

2、在 React 中,父子组件之间可以使用不同的方式进行通信。以下是几种常见的方式:

Props(属性):

父组件通过 props 将数据传递给子组件,子组件通过 props
接收父组件传递的数据。这是最常见的一种父子组件通信方式,适用于单向数据流的情况。

Callback(回调函数):

父组件可以将一个回调函数通过 props
传递给子组件,子组件在需要通知父组件时调用该回调函数。通过回调函数可以实现父组件和子组件之间的双向通信。

Context(上下文):

可以使用 React 的
Context(上下文)功能,在父组件中创建一个上下文对象,然后将数据通过上下文对象传递给子组件。子组件可以通过上下文来获取数据,而不需要通过多层嵌套的
props。
使用 Context 主要涉及到以下三个步骤:

1)创建一个 Context 对象:首先,我们需要使用 React.createContext() 方法创建一个 Context 对象。这个对象包含 Provider 和 Consumer 两个组件。
2)提供数据:然后,我们需要在一个父组件中使用 Context.Provider 组件将需要共享的数据传递给子组件。通过 value 属性来提供共享的数据。
3)使用数据:在需要共享数据的子组件中,使用 Context.Consumer 组件来接收提供的数据,并在 render 方法中通过回调函数来使用这些数据。

Redux 或其他状态管理库:

如果应用中需要进行大规模的状态管理和组件间通信,可以使用像 Redux 这样的状态管理库来管理全局状态。Redux 提供了一个全局的
store,让组件可以通过订阅和派发 actions 的方式进行状态管理和通信。

使用 Refs:

父组件可以通过创建 Refs 并将其传递给子组件,从而获取子组件的引用。这样父组件就可以直接操作子组件的方法和属性。
Refs 需要注意以下几点:

  1. Refs 只能在 Class 组件中使用,并通过 React.createRef() 方法来创建 Refs 对象。
  2. Refs 对象通过 ref 属性赋值给 React 元素,在组件内部通过 this.refName.current 来访问该元素或实例。
  3. 通过 Refs 访问到的 Dom 节点或 React 组件实例应该是经过渲染后的,因此 Refs 必须在组件 mount 完成后再访问。

Event Bus(事件总线):

可以使用事件总线模式来进行组件之间的通信。通过创建一个全局的事件总线对象,组件可以通过订阅和触发事件的方式进行通信。
`
事件总线(Event Bus)是一种在应用程序中进行组件间通信的模式。它通过使用中央化的事件中心来实现组件之间的解耦,从而简化了组件之间的通信流程。

在使用事件总线时,我们首先需要创建一个可以订阅事件和触发事件的中央事件中心。
这个事件中心可以是一个全局对象,也可以是一个专门创建的组件。然后,
在需要进行通信的组件中,可以订阅感兴趣的事件,以便在事件触发时执行特定的逻辑。
同时,在其他组件中,可以触发对应的事件,从而通知订阅了该事件的组件执行相应的操作。

以下是一个简单的示例,展示了如何使用事件总线进行组件之间的通信:

// 创建事件总线
const eventBus = new Vue();

// 组件A
const ComponentA = Vue.component('ComponentA', {
  template: `<div>
               <h2>Component A</h2>
               <button @click="sendMessage">Send Message</button>
             </div>`,
  methods: {
    sendMessage() {
      eventBus.$emit('message', 'Hello from Component A!');
    }
  }
});

// 组件B
const ComponentB = Vue.component('ComponentB', {
  template: `<div>
               <h2>Component B</h2>
               <p>{{ message }}</p>
             </div>`,
  data() {
    return {
      message: ''
    };
  },
  mounted() {
    eventBus.$on('message', (data) => {
      this.message = data;
    });
  }
});

// 创建Vue实例
new Vue({
  el: '#app',
  components: {
    ComponentA,
    ComponentB
  }
});
在上面的示例中,我们首先创建了一个事件中心对象 eventBus,它是一个 Vue 实例。
然后,在 ComponentA 组件中,当按钮被点击时会通过 eventBus 发送一个名为
 ‘message’ 的事件,并携带一个消息作为参数。在 ComponentB 组件中,我们通过
  eventBus.$on() 方法进行事件订阅,监听 ‘message’ 事件并在回调函数中更新组件
  的消息数据。

通过使用事件总线,ComponentA 和 ComponentB 组件之间实现了解耦,它们可以彼此
独立地发出和接收事件,实现了组件之间的通信。事件总线模式可以在多个组件之间
共享数据,提高组件的可复用性和可维护性。然而,需要注意的是,过度使用事件总线
可能导致应用程序的复杂性增加,因此应合理使用,并在需要时考虑其他更适合的通信方式。

`

需要根据具体场景和需求选择合适的通信方式,如果是简单的父子组件通信,props 和回调函数就足够了。如果是多层级或复杂的通信需求,可以考虑使用上述其他方式。

3、setState是同步的还是异步到,本质的执行机制原理是什么?

它的表现会因调用场景的不同而不同:在 React 钩子函数及合成事件中,它表现为异步;而在 setTimeout、setInterval
等函数中,包括在 DOM 原生事件中,它都表现为同步。这种差异,本质上是由 React 事务机制和批量更新机制的工作方式来决定的。

4、事件合成

假设一个大的 div 标签下面有 10000 个 小的 div 标签。现在需要添加点击事件,通过点击获取当前 div
标签中的文本。那该如何操作?最简单的操作就是为每一个 内部 div 标签添加 onclick 事件。有 10000 个 div
标签,则会添加 10000 个事件。这是一种非常不友好的方式,会对页面的性能产生影响。所以事件委托起了大作用。通过将事件绑定在 外面大的
div 标签上这样的方式来解决。当 内部 div 点击时,由事件冒泡到父级的标签去触发,并在标签的 onclick
事件中,确认是哪一个标签触发的点击事件。 无独有偶,React 的合成事件也是如此,React 给 document 挂上事件监听;DOM
事件触发后冒泡到 document;React 找到对应的组件,造出一个合成事件出来;并按组件树模拟一遍事件冒泡
这样就有一个问题,就是在一个页面中,只能有一个版本的 React。如果有多个版本,事件就乱套了。
但是在 17 版本之后,这个问题得到了解决,事件委托不在挂载到 document 上,而是挂在 DOM 容器上,也就是 ReactDom.Render 所调用的节点上。

在 React 中,setState 是用来更新组件状态的方法。setState 方法更新组件状态的过程可以简单地分为以下几个部分:

更新状态:setState
不会立即更新组件状态,而是把新状态合并到当前状态对象中,然后放到一个更新队列里等待批量更新。这也是为了避免多次更新状态,造成不必要的计算和渲染。

进入事务:当有一次事件循环完成时,React
就会从更新队列中取出所有的更新状态,将其合并为一个状态对象,并开始进行处理。这一过程称为进入事务。

协调和比对:React 开始协调这次更新所影响到的组件,并且将新的状态和旧的状态进行比对,找到需要更新的视图部分。

批量更新:React 会将所有需要更新的部分收集起来,然后一次性地进行更新,减少多次操作DOM引起的性能问题。

重新渲染:对于需要更新的部分,React 会计算出新的虚拟 DOM 对象,并用这个新的虚拟 DOM 对象来更新实例的真实 DOM 对象。

需要注意的是,React 会批量更新尽可能大的一部分更新。因此,可能会出现更新不是即刻生效的情况。除此之外,React
因为有一个「事务」的概念,因此,同时进行的几个 setState 方法调用只会触发一次视图更新。

总之,setState 的工作机制是通过一系列的流程,把需要更新的状态进行批量处理,最终渲染到界面中,避免多次操作 DOM
造成的性能问题。这种机制可以优化性能、最大程度地避免重新渲染组件,同时让 React 能够更好地管理和更新组件状态。

5、说一下虚拟Dom 与diff算法

React 的虚拟 DOM 实现了一种内存中的 DOM 表示,它是一个轻量级的 JavaScript
对象结构,用于描述组件的结构和属性。通过虚拟 DOM,React 可以实现高效的渲染和更新机制。

虚拟 DOM 的工作原理是这样的:

首先,React 组件在首次渲染时生成对应的虚拟 DOM 对象。这个虚拟 DOM 对象描述了组件的结构和属性。

当组件的状态发生变化时,React 会生成新的虚拟 DOM 对象。

接下来就是 diff 算法的执行。diff 算法将新旧虚拟 DOM 对象进行比较,找出两者之间的差异。

diff 算法会遍历虚拟 DOM
对象的每个节点,并判断它们是否相同。如果节点类型不同,则直接替换;如果节点类型相同但属性不同,则更新属性;如果节点有子节点,那么递归执行
diff 算法。

最后,React 根据 diff 算法找出的差异,将需要更新的部分转化为最小的 DOM 操作集合,然后批量执行这些 DOM
操作,最终来更新实际的页面视图。

通过 diff 算法,React 可以智能地只更新需要改变的部分,避免全局重绘,从而提高性能和渲染效率。

虚拟 DOM 和 diff 算法的好处在于:

减少了操作实际 DOM 的次数,提升了性能。 减少了页面渲染的开销,改善了用户体验。 更容易进行跨平台开发,因为虚拟 DOM 是平台无关的。
方便进行测试和调试,因为可以在内存中操作虚拟 DOM。 需要注意的是,虚拟 DOM
的引入会增加一定的计算和内存开销。但是,这是鉴于提升性能和可维护性的考虑。React 会针对虚拟 DOM
进行优化,并在适当的时机批量更新到实际 DOM。

总结来说,React 的虚拟 DOM 是一种内存中的 DOM 表示,通过 diff 算法实现高效的渲染和更新。虚拟 DOM 可以减少实际
DOM 操作次数,提高性能,同时带来了跨平台、测试和调试等方面的好处。

  • 41
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值