文章目录
-
- 什么是 React
- React生命周期
- React事件机制
- JSX
- state 和 props有什么区别?
- 组件通信
- context 多层级通信
- React Fiber
- 虚拟DOM、diff算法
- Hooks 链表
- React 18 新特性
- React性能优化方法
- React Hooks
- 自定义hook
- useEffect如何区分生命周期
- useEffect和useLayoutEffect的区别
- useMemo和useCallback
- setState的同步异步,调用setState后会发生什么
- React Router常用API
- React Router有几种模式,以及实现原理?
- 类组件和函数组件
- react组件设计模式
- 高阶组件(HOC)
- createElement和cloneElement的区别
- 受控组件和不受控组件
- 组件状态保存(类似vue的keep-alive)
- 路由懒加载及实现原理
- Redux是什么
- immutable
- 在React项目是如何捕获错误的?
- vue的react的区别
什么是 React
React用于动态构建用户界面的 JS UI库。
React特点:
- 使用
虚拟DOM和Diff算法,尽量复用DOM节点,减少与真实DOM的交互 - 使用
JSX,代码的可读性更好 组件化模式,提高代码复用率、且让代码更好维护声明式编程, 让编码人员无需直接操作DOM,提高开发效率
React声明式编程:我们只声明了我们想要的内容:比如一个包含用户姓名的无序列表,而不用关心具体的DOM操作。React会负责渲染和更新DOM,我们只需关注描述界面的声明式代码。
React的设计思想
-
组件化:每个组件都符合开放-封闭原则,封闭是针对渲染工作流来说的,指的是组件内部的状态都由自身维护,只处理内部的渲染逻辑。开放是针对组件通信来说的,指的是不同组件可以通过props(单项数据流)进行数据交互
-
数据驱动视图:UI=f(data),通过这个公式得出,如果要渲染界面,不应该直接操作DOM,而是通过修改数据(state或prop),数据驱动视图更新
-
虚拟DOM:由浏览器的渲染流水线可知,DOM操作是一个昂贵的操作,很耗性能,因此产生了虚拟DOM。虚拟DOM是对真实DOM的映射,React通过新旧虚拟DOM对比,得到需要更新的部分,实现数据的增量更新
React生命周期
React的生命周期:React实例从被创建到被销毁的过程,React组件中包含一系列勾子函数(生命周期回调函数), 会在特定的时刻调用。
只有 class 组件才有生命周期,因为 class 组件会创建对应的实例,而函数组件不会 。
React 生命周期主要包括三个阶段:挂载阶段,更新阶段,卸载阶段

class Test extends React.Component{
constructor(props){
// 构造函数
super(props)
this.state = {
}
}
// 初始化,更新时会调用
static getDerivedStateFromProps(props,state){
// 必须返回一个对象,会和state合并
return {
}
}
// 初始化渲染时使用
componentDidMount(){
}
// 组件更新时调用 返回false 不更新
shoudComponentUpdate(prevProps,nextState){
return true }
// 组件更新时调用,返回的值会设置在componentDidUpdate的第三个参数
getSnapshotBeforeUpdate(prevprops,nextState) {
return ''}
// 组件更新后调用
componentDidUpdate(preProps,preState,valueFromSnaspshot){
}
// 组件卸载时调用
componentWillUnmount() {
}
// 组件抛出错误
static getDerivedStateFromError(){
}
}
挂载阶段
挂载阶段:组件实例被创建和插入 DOM 树的过程
- constructor 初始化阶段,可以进行state和props的初始化
- static getDerivedStateFromProps 静态方法,不能获取this
- render 创建虚拟DOM的阶段
componentDidMount 第一次渲染后调用,挂载到页面生成真实DOM,可以访问DOM,进行异步请求和定时器、消息订阅
更新阶段
当组件的props或state变化会触发更新
- shouldComponentUpdate 返回一个布尔值,默认返回true,可以通过这个生命周期钩子进行性能优化,确认不需要更新组件时调用
- render 更新虚拟DOM
- getSnapShotBeforeUpdate 获取更新前的状态
- componentDidUpdate 在组件完成更新后调用,更新挂载后生成真实DOM
当组件的props或state变化会触发更新
卸载阶段
- componentWillUnmount 组件从DOM中被移除的时候调用,通常在这个阶段清除副作用,比如定时器、事件监听等
错误捕获
- static getDerivedStateFromError 在errorBoundary中使用
- render是class组件中唯一必须实现的方法
重要的勾子
render:初始化渲染或更新渲染调用。componentDidMount:在组件挂载成功之后调用,该过程组件已经成功挂载到了真实 DOM 上。一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息componentWillUnmount:在组件卸载成功之前调用,做一些收尾工作, 如:清理定时器、取消订阅消息
已经废弃的勾子
componentWillMountcomponentWillReceivePropscomponentWillUpdate
React事件机制
什么是React事件
React基于浏览器的事件机制实现了一套自身的事件机制,它符合W3C规范,包括事件触发、事件冒泡、事件捕获、事件合成和事件派发等


React事件和普通的HTML事件有什么不同?
- 对于事件名称命名方式,原生事件为全小写,react 事件采用小驼峰camelCase;
- 对于事件函数处理语法,原生事件为字符串,react 事件为函数;
<button onclick="alert('Button clicked')">Click me</button>
function MyComponent() {
return (
<button onClick={
()=>{
alert('Button clicked')}>Click me</button>
);
}
- react 事件不能采用 return false 的方式来阻止浏览器的默认行为,而必须要地明确地调用preventDefault()来阻止默认行为。
为什么React事件不能通过return false阻止事件的默认行为?
因为React基于浏览器的事件机制实现了一套自己的事件机制,和原生DOM事件不同,它采用了事件委托的思想,通过dispatch统一分发事件处理函数
React怎么阻止事件冒泡
- 阻止合成事件的冒泡用e.stopPropagation()
- 阻止合成事件和最外层document事件冒泡,使用e.nativeEvent.stopImmediatePropogation()
- 阻止合成事件和除了最外层document事件冒泡,通过判断e.target避免
React事件是 react 模拟原生 DOM 事件所有能力的一个事件对象,其优点如下:
- 兼容所有浏览器,更好的跨平台;
- 将事件统一存放在一个数组,避免频繁的新增与删除(垃圾回收)。
- 方便 react 统一管理和事务机制。
事件的执行顺序为原生事件先执行,合成事件后执行,合成事件会冒泡绑定到 document 上,所以尽量避免原生事件与合成事件混用,如果原生事件阻止冒泡,可能会导致合成事件不执行,因为需要冒泡到document 上合成事件才会执行。
JSX
JSX 是 JavaScript 语法扩展,可以在JS中编写XML的语言。它不能被浏览器直接识别,需要通过webpack、babel之类的编译工具转换为JS执行。
JSX是React.createElement的语法糖,使用JSX等价于React.createElement,React.createElement将返回一个ReactElement的js对象,编译工作交由babel操作
JSX 和 React 是相互独立的东西。JSX 是一种语法扩展,而 React 则是一个 JavaScript 的库。
import React from 'react';
//JSX不是字符串, 也不是HTML/XML标签,最终产生的就是一个JS对象
var ele = <h1>Hello, JSX!</h1>
// 等价于
var element = React.createElement(
"h1",
null,
"Hello, world!"
);
为什么在文件中没有使用react,也要在文件顶部import React from “react”?
只要使用了jsx,就需要引用react,因为jsx本质就是React.createElement
为什么React自定义组件首字母要大写?
从jsx到真实DOM需要经历jsx->虚拟DOM->真实DOM。如果组件首字母为小写,它会被当成字符串进行传递,在创建虚拟DOM的时候,就会把它当成一个html标签,而html没有app这个标签,就会报错。组件首字母为大写,它会当成一个变量进行传递,React知道它是个自定义组件就不会报错了
React组件为什么只能有一个根元素?(React组件为什么不能返回多个元素)
React的虚拟DOM是一个树状结构,树的根节点只能是1个,如果有多个根节点,无法确认是在哪棵树上进行更新
state 和 props有什么区别?
-
props是传递给组件的(类似于函数的形参),是父组件向子组件传递数据的方式,state是在组件内被组件自己管理的(类似于在一个函数内声明的变量), 代表了随时间会产生变化的数据,应当仅在实现交互时使用 -
props 在组件内部是不可修改的,但 state 在组件内部可以进行修改
-
组件可以选择把它的 state 作为 props 向下传递到它的子组件中
组件通信
单层级通信
- 父组件给子组件通信,传递props
- 子组件向父组件通信,使用回调函数(父组件向子组件传递一个函数,子组件在适当时机调用并传入自身的值或函数,这样父组件就可以拿到子组件传过来的参数了)
还可以借助forwardRef 和 useImperativeHandle 实现父组件直接访问并操作子组件内部某些特定DOM元素或者自定义的方法。具体来说,forwardRef 用于将 ref 传递给函数组件,而 useImperativeHandle 则是用来定制函数组件暴露给父组件的实例方法或属性。
下面是一个简单的示例,展示如何使用 forwardRef 和 useImperativeHandle:
import React, {
forwardRef, useImperativeHandle, useRef } from 'react';
// 定义一个子组件,它接收父组件传递过来的ref
const ChildComponent = forwardRef((props, ref) => {
// 使用useRef创建一个内部引用,例如用于存储一个DOM元素
const internalRef = useRef();
// 在useImperativeHandle中定义子组件希望暴露给父组件的方法或属性
useImperativeHandle

本文全面介绍了React,包括其特性、生命周期、事件机制等。阐述了React的设计思想,如组件化、数据驱动视图等。还讲解了Fiber架构、虚拟DOM和diff算法,以及组件通信、状态管理等内容。同时对比了Vue和React的异同,为开发者提供了深入了解React的参考。
最低0.47元/天 解锁文章
1808

被折叠的 条评论
为什么被折叠?



