react基础技术栈
-
- Props和组件间传值,插槽
- 生命周期
- [ref 和 context](#ref 和 context)
- 函数组件和hook
- 高阶组件
- React性能问题
- React-route的三个版本
- 状态管理
react项目构建
-
使用官方的脚手架
通过npx create-react-app 能创建一个最基本的react项目。但不同于vue的创建,只做了react基本的搭建和构建,没有配上任何路由和状态管理。项目使用webpack构建
-
使用一些市场上的集成脚手架
典型的比如umi。这一类脚手架创建出来的项目会集成好很多功能,比如路由,mock
两个核心库:
react:React核心库,提供react的个个功能
React-dom : 提供一些dom操作方法用于把react创建出来的react对象挂载到真正的htmldom中,或者从htmldom中卸载。核心作用类似于vue的mount。
react项目组件关系
组件化开发,定义一个基本组件得有两个东西,一个是组件html模版,一个是数据和方法。
区别于vue有专门的.vue写组件,react组件分为两类:一类是函数组件,一类是class组件,就跟vue3,vue2一样的版本。react老版本用的是class组件,新版本用的是函数组件。
可以在js中写html是因为jsx
jsx的特点:
- 直接在js中混用
React项目利用babel做了对js的编译,所以我们是可以直接在js里写jsx的。 - 写法接近js
jsx几乎和js一样,不同的是可以更方便的写html在js里,写在js里的html最后会被编译成一个js对象,我们也可以用react自带creatElement创建这个对象
jsx里面渲染不同内容的区别
react的事件绑定
规则模式 :
1.类似原生,on +方法名 (首字母大写)
2.一定要赋值给事件一个方法

react事件绑定的特别注意问题:
- 不做处理的情况下,this会指向Undefined
- 给到事件绑定的一定得是一个方法,不要直接调用方法,不然就是这个方法的返回值了,一定不能像vue里面直接调用这个方法,调用方法只会在页面初次渲染指向方法。
事件绑定其他操作
1.传递参数
2.获取事件对象
3,阻止默认行为,冒泡等
传递参数:借助bind()方法
事件对象:当我们没有传任何参数时,事件对象就是第一个参数,如果传了参数,事件对象就是最后一个参数。
阻止默认行为,冒泡:跟原生的一样
React组件的响应式数据
类组件响应式数据的定义
响应式数据定义在类的state属性中。
react响应式体系的原理
1、react不能像vue一样直接修改 触发更新
2.react修改能改值,但无法触发更新,因为react没有像vue一样监听get和set,而是在调用setState的时候调用react的更新操作
setState工作流程图解
关键点:
- 通过浅合并来修改数据
- 调用setState方法会触发更新,修改state并不会触发更新
setState是一个异步操作,所以如果我们要获取修改后的值,需要在setState的第二个参数里获取(这是我们对数据修改完成之后的操作)
PureComponent下对于对象和数组的修改
因为PureComponent会根据state是否改变来决定是否更新,而我们对于对象数组这样的引用类型判断是否改变的原理是看内存地址,而不是内容。所以我们PureComonent下修改对象和数组,一定要赋予一个新对象,所以一般我们不直接操作原对象,而是先拷贝一份,再进行操作
条件渲染和列表循环
React没有vue一样的指令,一切操作本质上都是我们通过运算生成不同的内容,拿去渲染,得到不同的页面
条件渲染的本质
原则:
1.react渲染undefined,null,空字符串,false不会渲染成任何内容
2.如果渲染一个jsx编写的html元素,就会渲染成页面上的内容
列表循环的本质
原则:
1.渲染一个数组会把数组里的每一项单独取出渲染
2.那么我们编写一个里面存放的都是html结构的数组,就会渲染成列表
vue指令开发与react的jsx开发
vue:各种效果用指令编写,对于简单的控制非常容易
react:各种效果都通过逻辑运算产出对应的内容渲染,能够完整控制整个过程
react的思想
1.更少的封装,更高的自由度,能够让使用者更加高度的去自定义实现,不用像vue一样必须遵守规则,在这里只需要遵守js规则
2.纯粹的js,不用去背什么特殊指令
表单绑定
React中很多思路都是按原生的操作区做的,表单绑定也是如此
原生表单获取表单输入值,可以通过监听input,change等事件,然后获取e.target.value
如果要设置表单的值,通常设置value属性,如果是选择框则是checked属性
1.受控组件(添加value属性)
javascript
<input value={this.state.inputValue} onChange={...} />
- React完全控制输入框的值
- 输入框的值始终与state保持同步
- 可以实现额外的值验证和处理
- 更容易实现表单处理和数据同步
2.非受控组件(不添加value属性) - 浏览器自己管理input的状态
- React无法直接控制输入框的值
- 可能导致状态不同步的问题
推荐使用受控组件
javascript
<input
value={this.state.inputValue}
onChange={(e) => {
// 只允许数字输入
const newValue = e.target.value.replace(/[^0-9]/g, '');
this.setState({ inputValue: newValue });
}}
/>
如果不使用value属性,这样的控制就很难实现。因此,在React中推荐使用受控组件模式来处理表单输入。
普通输入框input的双向是设置这个value的值就好了,然后这个选项框,复选框或单选框它们的value是选项的值,所以是否勾选是用check表示的,它们的双向是怎么做的呢
Props和组件间传值,插槽
props是react中的核心
在react中,一切写着组件上的属性和子节点都被规划为了props。
所以props是react很多功能的根本。父子传值,插槽全都是基于props,不像vue有事件监听,emit,专门的插槽这一类东西。
props的类型验证和默认值
有一个封装的库可以省去编码校验 npm i proptypes
模拟vue中的插槽
插槽本质上讲就是子组件的html内容需要父组件传入,在jsx的加持下,可以把html像普通的字符串,数字一样传递,所以插槽只需要直接作为props传入就行。
子往父传值
react中的样式操作
class类名设置
1.必须写为className
2.类名和样式写在css文件里
3.必须接收一个字符串
style内联
不能像原生一样写成字符串,必须写成对象
第一个{}代表里面的内容按照js去执行。第二个{}表明执行一个对象。
要css只在组件中生效,不在全局都生效。要创建 组件名-module.css 文件。
有一个第三方库 npm i classnames 可以避免麻烦的样式操作
生命周期
严格模式
严格模式只在开发模式下生效,生产上线时会去除,作用简要概括有两方面的作用
1.检测一些危险的操作(比如使用已经废弃api和不推荐的api)
2.会把一些生命周期执行两次,来检查额外副作用(比如render)
重点生命周期
render :通过render函数的执行来决定组件渲染什么内容,所以无论更新还是初次挂载都必须执行render
componentDidMount :组件挂载完成,一般用来做一些页面初始化操作,比如初始请求,echart绘制等,也就是vue的mounted里能做到事
shouldComponentUpdate :更新阶段调用,如果return false则不会执行render函数继续更新,从而达到阻止更新的效果,一般用来做性能优化。PureComponent不能喝shouldComponentUpdate一起用,要用Component,因为PureComponent效果是shouldComponentUpdate实现的。
**componentDidUpdate:**更新完成,等同于vue的updated
ref 和 context
ref 用于获取真实dom,和vue中的ref一个道理
注意事项:
1.ref必须在挂载后才能获取,通常在componentDidMount
2.ref获取类组件,不能获取函数组件
content 类似于vue的provider和injected,用于嵌套很深的爷孙组件之间传值。
注意事项:
子组件使用父组件创建的context对象,不能自己创建
函数组件和hook
1.函数组件没有生命周期
2.函数组件没有this
3.函数组件通过hook来完成各种操作
4.函数组件本身的函数体相当于render函数
5.props在函数的第一个参数接受
state的创建和更新
useEffect
定义副作用
不传第二个参数 = componentDidMount 和 componentDidUpdate
第二个参数传空数组 = componentDidMount
第二个参数数组里放摸=个数据 某= watch监听
useMemo
让一段计算在开始运行一次,后续只有依赖的数据发生变化时才重新运算
作用:
1.类似于vue的一个计算属性的效果
2.缓存一个数据,让其不会重新创建
useCallback
缓存一个方法,让方法不会每次更新都重新创建,和useMemo差不多。
当我们更新数据时,会重新执行APP(),很多方法虽然功能不变但重复执行了,优化性能
useRef - 函数组件中使用ref 。 还是为了获取真实dom
useContext - 更方便解析context的provider的数据
高阶组件
如果是ui内容和操作的复用我们会使用组件,但如果是单纯逻辑的复用,写为组件不免麻烦
什么时候用高阶组件
组件:组件是既包含了ui界面的复用,也包含了逻辑的复用
高阶组件:高阶组件只是复用操作逻辑,运算
React性能问题
React最大的一个性能问题就是 -React的某个组件的更新会连带着他的子组件一起更新。
所以我们需要解决这个问题:
1.react源码层面上尽量弥补这个问题
2.让子组件只做合理的更新
React的时间切片
Vue有依赖收集,做到了最小的更新范围,而React没有做这个事情,所以React要更新,就会有很大的diff算法对比和计算工作。这大的更新量,虚拟dom比对和计算会花很大时间,这样可能会阻塞住浏览器的工作,导致页面长时间白屏。React为了解决这个问题选择另一种策略-时间切片,也就是先计算一部分更新, 然后让渡给渲染进程渲染,然后再进行下一步更新。以此往复。这样我从使用者的角度,就不会出现长时间白屏了。
避免父组件数据更改导致子组件更新
父组件更改导致子组件更新是最大的问题
- PureComponent 和 React.Memo
避免state同样的值产生更新
- 避免state修改为同样的值,而产生无意义更新(PureComponent,函数组件本身就会判断)
props
如果组件使用了PureComponent或者React.Memo,虽然已经做到了如果父组件传的props没改变,就不会更新,但是我们 特别注意父组件传入的方法,对象,数组这样的引用类型
- 用useCallback包裹传递给子组件的方法
- 非state对象,数组数据,要用useMemo包裹起来
React-route的三个版本
1.React-router :服务端渲染使用
2.React-router-dom :浏览器端渲染使用
3.React-router-native :React-native混合开发使用
react-router使用步骤
1.通过BroserRouter 或者 HashRouter 包裹要使用路由的根组件
2.使用Routes组件,定义具体路由显示区域
3.使用Route组件,定义具体路由规则
4.使用NavLink 或者 Link组件,定义调整链接
react-router提供的一些其他重要组件
1.Navigate - 路由重定向
2.Outlet ,嵌套路由的子路由显示处
react的全局插件使用方式
React中没有vue那样的vue.use方法,react中使用一个插件,库,都是引入一个组件,然后把要使用该插件的部分包起来
动态路由和嵌套路由
- 嵌套路由
- 动态路由
获取路由参数

-
params参数
- query参数
- location参数
- query参数
js控制跳转路径
V6 - useNavigate
异步路由
React做异步路由,要配合到react本身的一个方法-lazy和一个组件suspense
状态管理
- React,没有专门的状态管理库,都是通用的js状态管理库,所以我们首先创建一个全局的数据储存和管理工具
- 通过其他工具,数据的修改能触发react页面的更新
react状态管理相关库
redux创建仓库
javascript
// store.js
import { createStore } from 'redux'
function counterReducer(state = { value: 0 }, action) {
switch (action.type) {
case 'increment':
return { value: state.value + 1 }
default:
return state
}
}
const store = createStore(counterReducer)
// 组件中使用
import { useSelector, useDispatch } from 'react-redux'
function Counter() {
const count = useSelector(state => state.value)
const dispatch = useDispatch()
return (
<button onClick={() => dispatch({ type: 'increment' })}>
{count}
</button>
)
}