react优点:组件化、虚拟DOM、JSX语法、单向数据流、兼容性好
#react18新特性
服务器组件
:将组件的渲染逻辑从客户端移动到服务器端,以更好地利用服务器资源并发模式的改进
:1、更好的错误处理(引入了新的错误边界机制);2、更可预测的渲染和更新行为(改进任务调度算法和批处理机制);3、更好的可中断和恢复能力(Fiber协调引擎)自动批量更新
:1、调用堆栈:React跟踪组件函数的调用过程,将脏组件标记为dirty
,延迟更新操作。2、优先级:React为状态更新分配优先级,按照优先级进行调度和执行。
#react生命周期
组件挂载时:
挂载阶段组件被创建,然后组件实例插入到DOM中,该过程只发生一次
- constructor() 组件构造函数
- componentWillMount dom树开始挂载前
- static getDerivedStateFromProps() 静态方法;接收两个参数:props接收的参数和state组件状态
- render() 根据传参props、state状态开始渲染组件
- componentDidMount() dom树挂载完成
组件更新时:
- static getDerivedStateFromProps()
- shouldComponentUpdate() 比较props、state,来确定返回true/false;false组件更新停止;
- render()
- getSnapshotBeforeUpdate() 更新前
- componentDidUpdate() 更新后
组件卸载时:componentWillUnmount() 将要卸载
错误处理:
- static getDerivedStateFromProps()
- componentDidCatch() 抛出错误,接收两个参数:error、info
#React发起网络请求在哪个生命周期
我一般在componentDidMount
- 异步请求,最好放在componentDidMount中去操作
- 同步的状态改变,可以放在componentWillMount中
#React中可以在render访问refs吗
不可以,render阶段DOM还没有生成,无法获取 DOM。需要在componentDidMount() dom数挂载完之后
#Fragment
概念:Fragment作为根标签包裹元素,Fragment不会有任何元素渲染;
#获取组件DOM
-
1 ref
<h2 ref="hello">Hello World</h2>
-
2 createRef()
import React, { PureComponent, createRef } from 'react'
export class App extends PureComponent {
constructor() {
super()
// 提前创建一个ref对象
this.titleRef = createRef()
}
getDom() {
console.log(this.titleRef.current) // <h2>Hello World</h2>
}
render() {
return (
<div>
<h2 ref={this.titleRef}>Hello World</h2>
<button onClick={() => this.getDom()}>获取DOM</button>
</div>
)
}
}
export default App
#React事件代理/原理
- 事件机制/委派:把所有的事件绑定到结构的最外层document使用统一的事件监听器
- 自动绑定:自动绑定this为当前组件
#react事件机制
核心:document处监听了所有的事件
click事件不是绑定到了div的真实DOM上,而是在document处监听了所有的事件,当事件发生并且事件冒泡到document处。这样减少了内存的消耗
#组件
#函数组件/类式组件区别
最大的区别:有无状态
、生命周期、class
- 函数组件-面向函数式编程
# 通过函数创建;无状态组件;场景:组件不需要管理state
- 类式组件-面向对象编程
# 基于ES6语法class创建;通过extends React.component得到的组件;
# 补充:还有React.createClass({})创建
区别
- 类组件有生命周期,函数组件没有
- 类组件需要继承 Class,函数组件不需要
- 类组件内部可以定义并维护
state
, 函数组件为无状态组件
#高阶组件HOC/Render props/hooks区别
- HOC
# 概念:高阶组件(HOC)是一个函数,传入一个组件返回一个新组件,并且是一个纯函数没有副作用
# 优点:代码复用、逻辑抽象
- Render props
# 组件之间的代码共享props
- hooks
# hooks作用:1 组件内部有了维护状态的能力;2 组件的逻辑复用能力;通常函数名字都是以use开头
#PureComponent纯组件
PureComponent:对props和state浅层比较,跳过不必要的更新,提高组件性能
补充:浅层比较原理:只做对象的每个key的引用比较,不深层遍历比较
#react创建组件
- ES6 class创建组件
class MyComponent extends React.Component {
render() {
return Hello World!;
}
}
- React.createClass创建组件
var MyComponent = React.createClass({
render() {
return Hello World!;
}
});
- 函数组件
function MyComponent() {
return Hello World!;
}
#Redx&react-redux
#Redux--了解即可
Redux概念:js状态容器;构建一致化的应用,运行与不同环境;并且体积小,只有2KB
Redux优点:
- 状态的集中管理
- 任意页面与组件之间的数据传递
- 状态管理的可预测
- 数据的本地化缓存提升性能
三大核心:
- 核心1:store存放数据仓库:整个应用的state被存储在一颗object tree中,并且这个object tree只存在于唯一一个store中
-
核心2:State数据:唯一改变state的方法就是触发action,action是一个用于描述已发生事件的普通对象
-
核心3:使用纯函数来执行修改:接收先前的state和action,并且返回新的state;
// dispatch唯一改变state的方法,通过提交action改变;是同步操作
store.dispatch(action)
// reducer 它负责对action变化进行分发和处理, 最终将新的数据返回给 store
#react-redux--要熟练
# 概念:是Redux官方出的用于配合React的绑定库;更方便的读取react store的数据
# 两个核心成员:Provider、Connect
- Provider
概念:Provider是一个组件,作用:使得整个app都能获取到store中的数据;需要包裹整个结构
- Connect
作用:接收Provider提供的store来获取的state;
- 使用
// index.js
root.render(
<Provider store={store}>
<App3 />
</Provider>
);
// store.js
import { createSlice } from '@reduxjs/toolkit'
export const counterSlice = createSlice({
name: 'counter',
initialState: {
num: 0
},
reducers: {
add: state => {
state.num += 1
},
decrement: state => {
state.num -= 1
},
// action传值
setNum: (state, action) => {
state.num = action.payload
}
}
})
//
export const { add, decrement, setNum } = counterSlice.actions
export default counterSlice.reducers
// 页面使用
import { useDispatch, useSelector } from 'react-redux';
const dispatch = useDispatch()//修改值
const num = useSelector(state => state.counter.num)//获取值
dispatch(add())//修改值
#React-Fiber
概念: React 16 中新的协调引擎,是协程。
-
为什么出现:在 React 16以前,更新过程是同步的,js执行占用主线程,虚拟树计算阻塞了浏览器的渲染。React Fiber很好的解决这个问题;
-
具体怎么做的:Fiber把耗时长任务拆分成很多小任务(执行时间短);功能有:1 不同任务分配优先极; 2 更新时能暂停、终止渲染任务
#组件通信
React组件间通信常见的几种情况:
- 1 父子组件通信
- 2 嵌套关系组件通信
- 3 非嵌套关系的组件通信--事件总线eventbus、redux
#父子组件通信
- 父传子
//子组件:props接收
<p>{props.name}</p>
//父组件:变量传递
<child name="react"></Child>
- 子传父
//子组件:props.callback(msg)
//父组件:callback(msg){console.log(msg)}
#嵌套关系组件通信
createContext实现;
- .Consumer包裹传递参数
const BatteryContext = createContext();
<BatteryContext.Consumer>
{
//传递的数据data=..
}
</BatteryContext.consumer>
- .Provider接收孩子组件数据
<BatteryContext.Provider value={data}>
<Child></Child>
</BatteryContext.Provider>
#非嵌套关系组件通信:
react-redux等进行全局状态管理
#React-Router路由
#路由原理
补充:路由模式:HashRouter、BrowserRouter
- HashRouter:基于hash :通过监听hashchange事件,感知hash的变改变hash 可以直接通过windows.location.hash=xxx
- BrowserRouter:基于H5 history:改变url可以通过history.pushState,会将URL压入堆栈,同时能够应用**history.go()/history.back()**等API
// 浏览器路由:history API控制路由跳转
<BrowserRouter basename=" /calendar">
<Link to=" /today">
</BrowserRouter>
// hash路由;通过URL的hash属性来控制路由跳转
<HashRouter basename={string} getUserConfirmation={func}hashType={string}/>
补充:hash类型有:slash 路由就是#/
;noslash 路由就是#
;hashbang #!/
#实现路由切换
路由跳转:
- 事件跳转:this.props.history.push('路由')
- 标签跳转:
<Link to="Home">to Home</Link>
类;似a标签的形式;
Link与a标签区别:
- Link一般配合route使用,阻止了a标签默认事件,link区别在于只会匹配对应的route的更新,a会整个页面更新;
<Route>
路由组件、<Switch>
是将路由组件分组;Redirect
是重定向;
Route中的exact是精确匹配,防止前面有/匹配;
<Switch>
<Route exact path={"/home"} component = { Home }></Route>
<Route path={"/user"} component = { User }></Route>
<Redirect to='/home/goods'/>
</Switch>
#获取URL的参数和历史对象
- 获取get传参:调浏览器api,URLSearchParams
- 获取动态路由传值:this.props.match.params
- 获取query/state传值:this.props.location.state、this.props.location.query
补充获取历史对象:useHistory API、this. props.history
#hooks
hooks作用:1组件内部有了维护状态的能力;2组件的 逻辑复用能力
- useState 让函数式组件拥有状态
const [count, setCount] = useState(0);//变量、更新变量的方法
useState原理:
- useEffect 模拟生命周期:componentDidMount(return前) shouldComponentUpdate(监听更新) componentWillUnmount(return里面)
useEffect(() => {
// 在此可以执行任何带副作用操作
return () => { // 在组件卸载前执行---
// 在此做一些收尾工作, 比如清除定时器/取消订阅等
}
}, [stateValue]) // []空代码不监听,[变量]检测数据更新
- useContext 共享状态钩子:一种组件间通信方式, 常用于爷孙组件传值
- userRef 存储组件属性
import React, { useRef, useEffect } from "react"
function App () {
//声明绑定的元素/组件
const pRef = useRef(null)
const testRef = useRef(null)
useEffect(() => {
//.current获取到的dom对象
console.log(pRef.current)
console.log(testRef.current)
}, [])
return (
<div>
//通过ref绑定元素/组件
<Test ref={testRef} />
<p ref={pRef}>this is p</p>
</div>
)
}
- memo-性能优化,缓存组件
# 作用:缓存组件,解决父组件不传任何值,影响子组件刷新问题(原理:默认是全等对比,默认空props也是不全等的,因此刷新子组件);
# 仍存在问题:父传子自定义的静态方法,仍然会照成子组件的刷新(原理:静态方法是闭包,默认每次的都不一样);需配合useCallback解决
- useCallback-性能优化,缓存组件
# usecallback缓存函数;,配合memo使用,解决memo中传自己方法导致子组件刷新问题;
- useMemo-性能优化,缓存组件
# usememo缓存值,计算然后再返回值的函数,函数中需要return
#useState使用数组而不是对象
如果是对象,解构赋值时那个变量就写死了。如果是数组,就可以自定义设置变量名来解构
#usecallback/usememo区别
react性能优化hook;
- 区别1: usecallback缓存函数,函数的调用不影响子组件更新;usememo缓存值(计算然后再返回值的函数,函数中需要return)
- 区别2:usecallback参数:函数/依赖项数组; usememo参数:函数(缓存需要计算的值)/依赖项数组
#useEffect新建项目后会更新两次
dom渲染完执行,代替生命周期
- 原因:兼容以前旧版本的React
- 发生场景:只发生在 development mode 中、并且是strict mode;解决办法:禁用 strict mode
#useState中的State里的对象值更新会重新渲染吗
- 不会,React中默认浅监听,当State值为对象时,栈中存的是对象的引用地址
#React Hook的使用限制有哪些
- 1、不要在循环/条件判断/嵌套函数中调用Hook;
- 2、在React的函数组件中调用Hook;
如何预防:
- 1 、可以引入 ESLint的进行语法检测
为什么不能在逻辑判断里写hooks:
- 1、无法保证 Hook 的调用顺序是稳定的,可能会导致状态更新的错误或不一致
#setState是同步还是异步
都有;
- 异步:比如在React 生命周期事件和合成事件中
- 同步:比如原生事件,addEventListener, setTimeout、setInterval等事件中,就只能同步更新。
#hook底层结构
-
底层结构基于链表,用于管理组件的状态并实现状态的共享和复用
-
每个组件实例都有对应的 Hooks 链表,用于存储其状态
-
Hooks 链表中的每个节点包含 Hook 值和与之相关的元信息
-
React 在组件渲染时根据 Hooks 的调用顺序来创建和管理 Hooks
#为什么React要用JSX
其实React 本身并不强制使用JSX。在没有JSX的时候,React 实现一个组件依赖于使用React.createElement函数;相比jsx更好用