一.为什么要学习react
声明式设计
高效灵活
组件化
单向数据流
虚拟dom
二.包含内容
React基础
React Hooks
React路由
Redux
组件库
Immutable
Mobx
React+TS
dva+umin
三.React介绍
![](https://i-blog.csdnimg.cn/blog_migrate/87ce239d18c9cdad85f168277b47e41d.png)
![](https://i-blog.csdnimg.cn/blog_migrate/07ebaf2f9ed81b4e284974d3cc63c764.png)
![](https://i-blog.csdnimg.cn/blog_migrate/5964effb30420f3e1bdceead8ce2dcb7.png)
![](https://i-blog.csdnimg.cn/blog_migrate/583588b7cd9a8ddb14c6ee389654a840.png)
四.create-react-app
![](https://i-blog.csdnimg.cn/blog_migrate/37b777ddb59c22f88acc8c13ed5e7acb.png)
![](https://i-blog.csdnimg.cn/blog_migrate/aba9bc50bf79300f6c8bfcc2b5a7ab55.png)
(1)删除node_modules,打包剩余的其他文件。拿到打包后的文件后,使用命令npm i 下载项目所需的依赖
![](https://i-blog.csdnimg.cn/blog_migrate/c4514966c9c2ccdeb57dbd2732526313.png)
(2)npm i -g nrm(npm仓库管理)
nrm -V(查看版本)
nrm ls(查看目录)
nrm use npm(切换到npm)
nrm use taobao(切换到taobao镜像)
![](https://i-blog.csdnimg.cn/blog_migrate/2ac48d5afc94668846d47909200ce13f.png)
五.编写第一个react应用程序
![](https://i-blog.csdnimg.cn/blog_migrate/a3b92e32662c41ec05b43ba68215d5b0.png)
jsx===js+xml
六.JSX语法与组件
JSX语法
![](https://i-blog.csdnimg.cn/blog_migrate/bc07472801280c4303e835733dddd224.png)
![](https://i-blog.csdnimg.cn/blog_migrate/e7b940220e5ef4648f50050a13692a32.png)
类组件
![](https://i-blog.csdnimg.cn/blog_migrate/1362f48e60ae12e5d1f0e6e98bbf4ce9.png)
![](https://i-blog.csdnimg.cn/blog_migrate/20476984b6464870a0c9786abc4a5ccf.png)
注意:(1)组件首字母必须大写
(2)只能含有一个根组件
(3)return要想回车必须加上小括号
函数式组件
16.8之前:无状态组件
16.8之后,react hooks
![](https://i-blog.csdnimg.cn/blog_migrate/5e801ff6b8127d6b179df598cf23f8ac.png)
组件的嵌套
组件的样式
![](https://i-blog.csdnimg.cn/blog_migrate/187332d3aad5cb3a36f16201c21dc9a7.png)
(1)react的js中不加上引号会被认为是变量,加上则为字符串
(2)属性得用驼峰写法
(3)样式属性得用className,label标签中的得用htmlFor
![](https://i-blog.csdnimg.cn/blog_migrate/a4068812661878cc9f3470784f7978bc.png)
![](https://i-blog.csdnimg.cn/blog_migrate/ce27e9992549e50f65d29f0d308574a0.png)
![](https://i-blog.csdnimg.cn/blog_migrate/99d944fe1771154e39b66ec24c9234bb.png)
事件处理
![](https://i-blog.csdnimg.cn/blog_migrate/2d9ea6e4220aa660808daa539e30b67e.png)
![](https://i-blog.csdnimg.cn/blog_migrate/945668df522e88396d55a867c965b4c5.png)
this指向:谁调用就执行谁
![](https://i-blog.csdnimg.cn/blog_migrate/fed381d81cb79d2129b0a3614f1f7544.png)
![](https://i-blog.csdnimg.cn/blog_migrate/e84f8b4db1ae4e8bd099b9dbdea104f3.png)
![](https://i-blog.csdnimg.cn/blog_migrate/cd717bf7cd4d096bd17112c1b6f36dec.png)
![](https://i-blog.csdnimg.cn/blog_migrate/71a19effcfa08a3e08074137557f8733.png)
Ref的应用
![](https://i-blog.csdnimg.cn/blog_migrate/9424a107d22b77c8db5a3475c58441b3.png)
![](https://i-blog.csdnimg.cn/blog_migrate/1be5b9c6ea85725a9cf2a832e8099c0a.png)
七. 组件的数挂载
状态
![](https://i-blog.csdnimg.cn/blog_migrate/4ffc28b044fc821b5ec8f1667d4a4c64.png)
![](https://i-blog.csdnimg.cn/blog_migrate/050349c10e9858d0134a3430ec7d6af6.png)
第一种方式:
![](https://i-blog.csdnimg.cn/blog_migrate/53b78ca8359fddb62d7a16bfeba51b67.png)
第二种方式:
![](https://i-blog.csdnimg.cn/blog_migrate/59edcf1ce934973fe29822667d066bd0.png)
![](https://i-blog.csdnimg.cn/blog_migrate/a6ed129f294e4cd42fcbfcd06e8c63ef.png)
列表渲染
![](https://i-blog.csdnimg.cn/blog_migrate/c02c4af8a99e168f28120c793814d6da.png)
![](https://i-blog.csdnimg.cn/blog_migrate/89387346f0b0781c0ddb903b49a17e4e.png)
![](https://i-blog.csdnimg.cn/blog_migrate/64883768b5660b7bb3a927ca31b1819b.png)
![](https://i-blog.csdnimg.cn/blog_migrate/8a3c85475c681dba8318dc5ac2476f3d.png)
todolist案例
let a=[1,2,3]
let b=[...a],深度复制,生成b这一个新数组
let c=a.slice(),不传参数的话等于把a复制给b,contact()也一样
不要直接修改状态,造成不可修改的错误
![](https://i-blog.csdnimg.cn/blog_migrate/44ad1b1b5b6cc88477a1c18b65b3a858.png)
![](https://i-blog.csdnimg.cn/blog_migrate/a2383f49294d53c04861f64e894ea351.png)
![](https://i-blog.csdnimg.cn/blog_migrate/816f6f9b5c25257fb8a03590d29078f9.png)
![](https://i-blog.csdnimg.cn/blog_migrate/7312a9020bb4a5c9ef59260aac11307d.png)
条件渲染
根据条件判断是渲染还是删除
![](https://i-blog.csdnimg.cn/blog_migrate/acccd38b3183588b9dc0bcdecb82feb8.png)
dangerouslySetInnerHTML
![](https://i-blog.csdnimg.cn/blog_migrate/f2f0716771e57ea93468df4c7e0e5f7a.png)
卖座影院案例
![](https://i-blog.csdnimg.cn/blog_migrate/f7e89137cc2fa4c2fa098a1bf461e334.png)
(1)发起请求
![](https://i-blog.csdnimg.cn/blog_migrate/e24f84fe22634a7ef2e1ff8f554339e9.png)
(2)模糊搜索:使用filter进行过滤,不改变原数组,可以使用备份,使得数组不会被覆盖。
setState状态
![](https://i-blog.csdnimg.cn/blog_migrate/683fbe9deeba9c8850151aef7a77bdf5.png)
![](https://i-blog.csdnimg.cn/blog_migrate/05ffceb73bf4352013f26f3d989d0a2a.png)
(1)在定时器中,setState是同步更新的,调用一次执行一次;
(2)在同步环境中,setState是异步更新的。首先会设置合并开关,把所有相同的过程合并,所以此时的状态没有改变,合并完之后执行,状态才会发生改变。
(3)setState的第二个参数可以得知setState状态的改变
![](https://i-blog.csdnimg.cn/blog_migrate/10b80e734c58bcf4d01e5626638a6f91.png)
![](https://i-blog.csdnimg.cn/blog_migrate/f6ecbff501bb3a12be2606ccab798cd9.png)
外面的盒子得固定高度(className="kerwinwrapper"),可以获取视口高度。
props属性
(1)props简单用法
![](https://i-blog.csdnimg.cn/blog_migrate/915f24b01416de14f82d16af52f66c15.png)
(2)用大括号表示js地盘:传变量,表达式,js数字,布尔值。
(3)props验证属性
![](https://i-blog.csdnimg.cn/blog_migrate/8e740f895099a960d8280829ac7ebed0.png)
默认属性·:
![](https://i-blog.csdnimg.cn/blog_migrate/5bd7c56c1b7b7b93ed2d5cbd0d319d5f.png)
(4)类属性和对象属性
对象属性需要new之后才能访问得到,直接定义在类上面的可以直接访问(类属性)
类属性可以加上static之后移到类中。
![](https://i-blog.csdnimg.cn/blog_migrate/10d1e175ddf55e354b0c320ce4772e75.png)
![](https://i-blog.csdnimg.cn/blog_migrate/d3cee7dd27c515595dc3572da01d555a.png)
(5)函数式组件props属性:通过形参实现
![](https://i-blog.csdnimg.cn/blog_migrate/df4e4dcadd156a1a20e19d1b13d206d7.png)
![](https://i-blog.csdnimg.cn/blog_migrate/e9ce3b0a475d2a952d2903ebad300544.png)
属性合并,传过来的属性在左边
![](https://i-blog.csdnimg.cn/blog_migrate/3618057fbdbe8df12d3bb313dfe95b75.png)
函数式组件props验证,直接挂载到函数身上
![](https://i-blog.csdnimg.cn/blog_migrate/b9d04165dd6902106ac45ffdad3c0e4f.png)
总结
![](https://i-blog.csdnimg.cn/blog_migrate/d25a5815edb87e7c2bd7b1a191d8c9c1.png)
八.表单中的受控组件和非受控组件
react中的onInput和onChange事件是一样的,原生js则不然。
非受控组件
(1)React要编写一个非受控组件,可以 使用 ref 来从 DOM 节点中获取表单数据,就是非受控组件。
(2)因为非受控组件将真实数据储存在 DOM 节点中,所以在使用非受控组件时,有时候反而更容易同时集成 React 和非 React 代码。如果你不介意代码美观性,并且希望快速编写代码,使用非受控组件往往可以减少你的代码量。否则,你应该使用受控组件。
(3)默认值
在 React 渲染生命周期时,表单元素上的 value 将会覆盖 DOM 节点中的值,在非受控组件中,你经
常希望 React 能赋予组件一个初始值,但是不去控制后续的更新。 在这种情况下, 你可以指定一个
defaultValue 属性,而不是 value 。
同样, <input type="checkbox"> 和 <input type="radio"> 支持 defaultChecked , <select>
和 <textarea> 支持 defaultValue 。
受控组件
![](https://i-blog.csdnimg.cn/blog_migrate/681bdd5f766b2825af4bf7f1fb8caf57.png)
![](https://i-blog.csdnimg.cn/blog_migrate/12deeea1fff0fede7d2735ed90074cd6.png)
![](https://i-blog.csdnimg.cn/blog_migrate/29fa2e3bdc39bb1cc0a80aedc2c08695.png)
![](https://i-blog.csdnimg.cn/blog_migrate/924bb51a77d996ac6e3cb477a02e6407.png)
![](https://i-blog.csdnimg.cn/blog_migrate/ef8c28b5481bc27b67c6d4c977191b75.png)
![](https://i-blog.csdnimg.cn/blog_migrate/2743e006210c5b21572a0f29f6d6d6a7.png)
![](https://i-blog.csdnimg.cn/blog_migrate/1d7fa6333d90e36633aeb6bbe1674317.png)
九.组件的通信方式
![](https://i-blog.csdnimg.cn/blog_migrate/56f2295bb95ddb63c62cc14ad691f683.png)
状态提升
(1)test.json(模拟后端接口数据)
![](https://i-blog.csdnimg.cn/blog_migrate/5cec7ba70bb24be680fde6fae3358439.png)
![](https://i-blog.csdnimg.cn/blog_migrate/28530bf1f0df8a9630c2e46bdae79816.png)
(2)app父组件
![](https://i-blog.csdnimg.cn/blog_migrate/5741b0aeebdfa93a56160fa2b4220eed.png)
![](https://i-blog.csdnimg.cn/blog_migrate/d0dfe1fcb856e18ecd89adafb4b8ef0a.png)
(3)电影项目
![](https://i-blog.csdnimg.cn/blog_migrate/864c6fae19f115c38cbddaa24f0e7663.png)
(4)电影细节
![](https://i-blog.csdnimg.cn/blog_migrate/3afdef18a5c8cf3eac2b2389c8f036a5.png)
发布订阅模式实现
(1)原生基本模式
![](https://i-blog.csdnimg.cn/blog_migrate/4c2f6c8ed6c21837f2582b1dcee7dd97.png)
(2)
![](https://i-blog.csdnimg.cn/blog_migrate/fa7111ac833308fec21de6ea3fde5353.png)
![](https://i-blog.csdnimg.cn/blog_migrate/8f08a6b4f052a76a8b238bada1c4f5a3.png)
![](https://i-blog.csdnimg.cn/blog_migrate/3dd6c7d866031efa7fd431db3ef05c7d.png)
![](https://i-blog.csdnimg.cn/blog_migrate/f69d5e509d424259d58f8997ffa5f66b.png)
context状态树传参
父组件为生产者,子组件为消费者
![](https://i-blog.csdnimg.cn/blog_migrate/250239facd6b006df8aa5b8266dbbac9.png)
![](https://i-blog.csdnimg.cn/blog_migrate/2312c66c1971ea3b1b643455bd677fa9.png)
![](https://i-blog.csdnimg.cn/blog_migrate/3cf7ec48c3b267be2c35d525b2c67a03.png)
![](https://i-blog.csdnimg.cn/blog_migrate/8363e493f97bb872ae0797ee081f2629.png)
![](https://i-blog.csdnimg.cn/blog_migrate/fdc01c8d0582795230c35cac340edf9c.png)
注意:GlobalContext.Consumer内必须是回调函数,通过context方法改变根组件状态
context优缺点:
优点:跨组件访问数据
缺点:react组件树种某个上级组件shouldComponetUpdate 返回false,当context更新时,不
会引起下级组件更新
插槽
子组件
![](https://i-blog.csdnimg.cn/blog_migrate/b7954d9236534ab5d9a08cad962d51b0.png)
父组件
![](https://i-blog.csdnimg.cn/blog_migrate/c43b5a261f2d5d2fd16b6ae0abcbc8b1.png)
优点:(1)为了复用
(2)一定程度上减少父子通信,在谁的的组件中,就可以使用它的状态
十.生命周期
初始化阶段
(1)componentWillMount:第一次上树前的最后一次修改状态机会,初始化状态的作用,不能获取真实dom
(2)render只能访问this.props和this.state,不允许修改状态(会出现死循环)和DOM输出,会执行多次
(3)componentDidMount:成功render并渲染完成真实DOM之后触发,可以修改DOM,只会执行一次
a.数据请求axios
b.订阅函数的调用
c.setInterval
d.基于创建完的dom进行初始化
运行阶段
(1)componetWillupdate:不能修改属性和状态
(2)render:只能访问this.props和this.state,不允许修改状态(会出现死循环)和DOM输出
(3)componentDidUpdate:可以修改DOM,获取DOM节点,会运行多次
![](https://i-blog.csdnimg.cn/blog_migrate/e42bb9a217ccd25aca75a4468d93200c.png)
(4)shouldComponentUpdate:return false会阻止render更新,使得组件得以优化
![](https://i-blog.csdnimg.cn/blog_migrate/9a6881c2f009fa542e324f5ba8efbe64.png)
![](https://i-blog.csdnimg.cn/blog_migrate/caa136e1faa5c0f10c8e67ec849f63ff.png)
render只能更新两次,旧的状态(上一个)与新的状态(下一个)
![](https://i-blog.csdnimg.cn/blog_migrate/9958e32efd3eec85aaf28e800f1708b5.png)
(5)componentWillReceiveProps:在父组件中更新才有效,只要父组件更新就会执行(多次)。子组件中,this.props.text是旧的状态。
![](https://i-blog.csdnimg.cn/blog_migrate/89797226c24bdd79ae335b2e37199e8a.png)
销毁阶段
componentWillUnmount:在删除组件之前进行清理操作,比如计时器和事件监听器
老生命周期的问题
(1) componentWillMount ,在ssr中 这个方法将会被多次调用, 所以会重复触发多遍,同时在这里如果绑定事件,将无法解绑,导致内存泄漏 , 变得不够安全高效逐步废弃。
(2) componentWillReceiveProps 外部组件多次频繁更新传入多次不同的 props,会导致不必要的异步请求
(3) componetWillupdate, 更新前记录 DOM 状态, 可能会做一些处理,与componentDidUpdate相隔时间如果过长, 会导致状态不太行
新的生命周期
(1)getDerivedStateFromProps:第一次的初始化组件以及后续的更新过程中(包括自身状态更新以及父传子) ,返回一个对象作为新的state,返回null则说明不需要在这里更新state
具体格式:
![](https://i-blog.csdnimg.cn/blog_migrate/c6c7220c705e58418474185d2356b40c.png)
初始化:修改状态,可能会被写固定了
![](https://i-blog.csdnimg.cn/blog_migrate/a9b3a4192152481906dbc04b62eb4596.png)
substring:(1)substring是用来截取字符串的,根据参数的个数不同,方法含义也不同;
(2)substring(0,2)这个只含开头不含结尾,因此截取是截取两个字符,从第一个到第二个字符,不包含第三个。
(3)substring(2)这个表示截掉前两个,得到后边的新字符串。
![](https://i-blog.csdnimg.cn/blog_migrate/1c56bffba2afe69df84ad2346a1ff4da.png)
在子组件中
![](https://i-blog.csdnimg.cn/blog_migrate/118f1ce2ead684fc4f158ac1c8c89a4d.png)
![](https://i-blog.csdnimg.cn/blog_migrate/f98bcc9ce07d99c0ac72d3552e6f4682.png)
(2)getSnapshotBeforeUpdate :取代了 componetWillUpdate ,触发时间为update发生的时候,在render之后dom渲染之前返回一个值,作为componentDidUpdate的第三个参数
(render之前,didUpdate之前)
![](https://i-blog.csdnimg.cn/blog_migrate/51e3b66187da797d3aea13cd30ac0697.png)
![](https://i-blog.csdnimg.cn/blog_migrate/8b5f65ddc34dec2d32a2b274c19ddca0.png)
value=100
![](https://i-blog.csdnimg.cn/blog_migrate/87a897a6151e602588158baa537a2546.png)
![](https://i-blog.csdnimg.cn/blog_migrate/e4f36a6f7db63a4ebb18e8074f19df0f.png)
![](https://i-blog.csdnimg.cn/blog_migrate/1bc1f429ed300a8de84890c0da231ee3.png)
react中性能优化的方案
(1)shouldComponentUpdate
控制组件自身或者子组件是否需要更新,尤其在子组件非常多的情况下, 需要进行优化。
(2)PureComponent
PureComponent会帮你 比较新props 跟 旧的props, 新的state和老的state(值相等,或者
对象含有相同的属性、且属性值相等 ),决定shouldcomponentUpdate 返回true 或者
false, 从而决定要不要呼叫 render function。
注意:
如果你的 state 或 props 『永远都会变』,那 PureComponent 并不会比较快,因为
shallowEqual 也需要花时间。
十一.React Hooks
使用hooks理由
(1) 高阶组件为了复用,导致代码层级复杂
(2) 生命周期的复杂
(3)写成functional组件,无状态组件 ,因为需要状态,又改成了class,成本高
useState(保存组件状态)
![](https://i-blog.csdnimg.cn/blog_migrate/64bcc550d9c6800b66c396d66ee27549.png)
![](https://i-blog.csdnimg.cn/blog_migrate/74cf253949780ceaf2aa0cb0eedea29f.png)
useEffect,类似于componentDidMount
(1)不要对 Dependencies 撒谎, 如果你明明使用了某个变量,却没有申明在依赖中,你等于向 React 撒了谎,后果就是,当依赖的变量改变时,useEffect 也不会再次执行, eslint会报警告
![](https://i-blog.csdnimg.cn/blog_migrate/631afc09aec1509752803bddb5e52401.png)
(2)组件销毁
![](https://i-blog.csdnimg.cn/blog_migrate/619bda8af6d4b20ac53035b99c06d2f1.png)
(3)useEffect和useLayoutEffect(存放到内存中)有什么区别?
简单来说就是调用时机不同, useLayoutEffect 和原来 componentDidMount & componentDidUpdate 一致,在react完成DOM更新后马上同步调用的代码,会阻塞页面渲染。而 useEffect 是会在整个页面渲染完才会调用的代码。
官方建议优先使用 useEffect
在实际使用时如果想避免页面抖动(在 useEffect 里修改DOM很有可能出现)的话,可以把需要操作DOM的代码放在 useLayoutEffect 里。在这里做点dom操作,这些dom修改会和 react 做出的更改一起被一次性渲染到屏幕上,只有一次回流、重绘的代价。
(4)useCallback(记忆函数)
防止因为组件重新渲染,导致方法被重新创建 ,起到缓存作用; 只有第二个参数 变化了,才重新声明一次(组件自身的状态发生变化方法才会重新渲染,要是与组件自身状态无关则不会重新创建,只会拿取先前缓冲的方法)
![](https://i-blog.csdnimg.cn/blog_migrate/238f396aee54cca54c4fc1f7560e9516.png)
![](https://i-blog.csdnimg.cn/blog_migrate/d24b115a7328554c8962c37618b120b6.png)
![](https://i-blog.csdnimg.cn/blog_migrate/b483a3f07b95e61931501d41f6d896fd.png)
![](https://i-blog.csdnimg.cn/blog_migrate/5749d2836f5e4499de6cb7b8aeadc5fd.png)
a.只有name改变后,这个函数才会重新声明一次
b.如果传入空数组,那么就是第一次创建后就被缓存,如果name后期改变了,拿到的还是老的name。
c.如果传入第二个参数,每次都会重新声明一次,拿到的就是最新的name
(5)useMemo 记忆组件
a.useCallback 的功能完全可以由 useMemo 所取代,如果你想通过使用 useMemo 返回一个记忆函数也是完全可以的。
useCallback(fn, inputs) is equivalent to useMemo(() => fn, inputs)
b.唯一的区别是:useCallback 不会执行第一个参数函数,而是将它(把创建的方法)返回给你,而 useMemo 会执行第一个函数并且将函数执行结果返回给你。所以在前面的例子中,可以返回handleClick 来达到存储函数的目的。
所以 useCallback 常用记忆事件函数,生成记忆后的事件函数并传递给子组件使用。而 useMemo 更适合经过函数计算得到一个确定的值,比如记忆组件。
![](https://i-blog.csdnimg.cn/blog_migrate/c0ff4fdd984861bbdedb70b8f570bdd4.png)
![](https://i-blog.csdnimg.cn/blog_migrate/66c57dedaf43266aeba969f7111ec636.png)
(6)useRef(保存引用值)
![](https://i-blog.csdnimg.cn/blog_migrate/142d828deb1190c4c4f7fd8f3ea67d27.png)
![](https://i-blog.csdnimg.cn/blog_migrate/778b4acfb61b197c089b026440deb7b4.png)
![](https://i-blog.csdnimg.cn/blog_migrate/76698cc651268a68d4b3f16b64c3c1d7.png)
使用useRef可以存放先前变量的值
![](https://i-blog.csdnimg.cn/blog_migrate/a321574867112e64ea53b65b13b4d0a7.png)
![](https://i-blog.csdnimg.cn/blog_migrate/ddc9acc61724db0b531ac863212acf0b.png)
(7)useContext(减少组件层级,跨级通信)
var GlobalContext= React.createContext()
![](https://i-blog.csdnimg.cn/blog_migrate/f732c054a0f301cb8f9640b936dd1e55.png)
![](https://i-blog.csdnimg.cn/blog_migrate/28ac48ebd4b9a86805d9d7713a517db0.png)
(8)useReducer(状态放在外面)
![](https://i-blog.csdnimg.cn/blog_migrate/9e85061954a6ae02d0cf1bf38806b16c.png)
![](https://i-blog.csdnimg.cn/blog_migrate/5c2dfdaa84845352acdace9685a6ce66.png)
(9)useReducer和useContext联合使用
![](https://i-blog.csdnimg.cn/blog_migrate/936ed2cb680cb8dcec10417ac6ce0325.png)
![](https://i-blog.csdnimg.cn/blog_migrate/7571dda43e95dcb5c7c6c67e683b0696.png)
![](https://i-blog.csdnimg.cn/blog_migrate/e7fa18434ecfafd14c5450c877a9d613.png)
![](https://i-blog.csdnimg.cn/blog_migrate/56f893ff55c50a444f5ddd969de5947f.png)
(10)自定义hooks
当我们想在两个函数之间共享逻辑时,我们会把它提取到第三个函数中。
必须以“use”开头吗?必须如此。这个约定非常重要。不遵循的话,由于无法判断某个函数是否包含对其内部 Hook的调用,React 将无法自动检查你的 Hook 是否违反了 Hook 的规则
![](https://i-blog.csdnimg.cn/blog_migrate/358961aad75ed8464b35da6a2dbad474.png)
![](https://i-blog.csdnimg.cn/blog_migrate/ef345f8fcea636fac48ebc1f2f3cebe3.png)
十二.React路由
1. 什么是路由?
路由是根据不同的 url 地址展示不同的内容或页面。
一个针对React而设计的路由解决方案、可以友好的帮你解决React components 到URl之间的同步映射关系。
2. 路由安装
https://reacttraining.com/react-router/web/guides/quick-start
![](https://i-blog.csdnimg.cn/blog_migrate/2052a014dfca1cb136918d6962102c00.png)
3. 路由使用(记得加上<Switch><Switch/>)
(1) 路由方法导入(可以定义一个路由文件,里面存放路由组件)
![](https://i-blog.csdnimg.cn/blog_migrate/c169783e066e8c49a55aaa2767e743cb.png)
(2)定义路由以及重定向(记得加上<Switch><Switch/>)
![](https://i-blog.csdnimg.cn/blog_migrate/6a2f4bd770cff9552fdd61c580d9a0f2.png)
模糊匹配
![](https://i-blog.csdnimg.cn/blog_migrate/3fc6a0b3d4bd7030a37a1ff31bd0b6a4.png)
精确匹配(exact)
![](https://i-blog.csdnimg.cn/blog_migrate/558496da2bfc075f9a3932b398b76d90.png)
a. exact 精确匹配 (Redirect 即使使用了exact, 外面还要嵌套Switch 来用)
b. Warning: Hash history cannot PUSH the same path; a new entry will not be added to the historystack,这个警告只有在hash 模式会出现。
(3)嵌套路由(不要精确匹配)记得加上<Switch><Switch/>
![](https://i-blog.csdnimg.cn/blog_migrate/9a61b202a4486c39e04c75da9056d2a1.png)
(4) 路由跳转方式
原生方式
![](https://i-blog.csdnimg.cn/blog_migrate/2b948a488fa86ed5060b0b52af21c870.png)
a. 声明式导航
<NavLink to="/films" activeClassName="active">films</NavLink>
b. 编程式导航
<Route/>路由中component组件会变成其的孩子,拥有history
类组件:this.props.history.push(`/center`)
函数组件:props.history.push(`/center`)
useHistory
![](https://i-blog.csdnimg.cn/blog_migrate/618d0f6499db804b672453bb63421c64.png)
(5)动态路由
a.动态路由传参:冒号是占位符不能省略
![](https://i-blog.csdnimg.cn/blog_migrate/757ec35cc286c8d533a8143f8f982fe1.png)
![](https://i-blog.csdnimg.cn/blog_migrate/1c81cecc6d10dd85aa39edeefed3a5c1.png)
b.query传参
![](https://i-blog.csdnimg.cn/blog_migrate/4d2916fef65c6e15cdac0db8cbf99b83.png)
![](https://i-blog.csdnimg.cn/blog_migrate/06697a19095fd0314632c5dabdbcda9c.png)
![](https://i-blog.csdnimg.cn/blog_migrate/a10dc54ab433212aa3e5e47d8c5c7674.png)
c.state传参
![](https://i-blog.csdnimg.cn/blog_migrate/266b31b3584925ad7bc6371f154b5bd5.png)
![](https://i-blog.csdnimg.cn/blog_migrate/92619c6c4c559fd40a449881ec36289f.png)
![](https://i-blog.csdnimg.cn/blog_migrate/ebf9fd7d3b458f33e5620c181a08fce9.png)
(6)路由拦截
![](https://i-blog.csdnimg.cn/blog_migrate/0d7d3a2a5bfa7d1393e62069fea55210.png)
(7)路由模式
HashRouter=>#,不能向后端发送数据,只存储在本地
BrowserRouter:可以向后端发送数据
![](https://i-blog.csdnimg.cn/blog_migrate/e29d9026441c4456e6249d9ae29a4853.png)
![](https://i-blog.csdnimg.cn/blog_migrate/a614a9c85105dccf171cfd6e9d86fa26.png)
(8) withRouter的应用与原理
不是所有的组件都是Router的孩子,如下
![](https://i-blog.csdnimg.cn/blog_migrate/45f3ad18ed253a1f6134de61c152f030.png)
Router路由组件才有history,match,location
![](https://i-blog.csdnimg.cn/blog_migrate/b736a187f569c9965d4165c977a7eb40.png)
withRouter为非路由组件提供路由组件的属性
![](https://i-blog.csdnimg.cn/blog_migrate/1f5b5ad4b66cc6c5b6ae505041483d02.png)
![](https://i-blog.csdnimg.cn/blog_migrate/6e144eb8e9a171314bc7d6fc396bf79b.png)
(9)跨域请求
a.cors,需要后端配合
b.jsonp,需要后端配合
c.反向代理:隐藏服务端(推荐)
https://facebook.github.io/create-react-app/docs/proxying-api-requests-in-development
正向代理:隐藏客户端
![](https://i-blog.csdnimg.cn/blog_migrate/652af50e48e8f72c1d82125681e19b8d.png)
在src下创建setupProxy.js,写入如下:
![](https://i-blog.csdnimg.cn/blog_migrate/5f9936c37554210d6b51b3c6ca21afa5.png)
![](https://i-blog.csdnimg.cn/blog_migrate/28038b58c0ee9272eeb3754943b8f048.png)
![](https://i-blog.csdnimg.cn/blog_migrate/1a027eaa36698645a1c3c509470cf18c.png)
(10)css样式
https://facebook.github.io/create-react-app/docs/adding-a-css-modules-stylesheet
创建css文件名后面必须加上module
class,id选择器(常用)
![](https://i-blog.csdnimg.cn/blog_migrate/e380a95661641d32c8357e76ab359c84.png)
![](https://i-blog.csdnimg.cn/blog_migrate/bcd018cbc82053d2dcac9d68918059c8.png)
![](https://i-blog.csdnimg.cn/blog_migrate/07ce91fa8a7003d6574a5b54782032ef.png)
![](https://i-blog.csdnimg.cn/blog_migrate/3fa7433a12ec5c70b783bb2548d177e8.png)
全局独一不会被影响
![](https://i-blog.csdnimg.cn/blog_migrate/56db3fe521be708e0107eb5749acf947.png)
十三.Flux与Redux
Flux 是一种架构思想,专门解决软件的结构问题。它跟MVC架构是同一类东西,但是更加简单和
清晰。Flux存在多种实现(至少15种)
https://github.com/voronianski/flux-comparison
Facebook Flux是用来构建客户端Web应用的应用架构。它利用单向数据流的方式来组合React
中的视图组件。它更像一个模式而不是一个正式的框架,开发者不需要太多的新代码就可以快速的上手Flux。
![](https://i-blog.csdnimg.cn/blog_migrate/c3fdbc3721105095cba5d1e3d9c195c0.png)
![](https://i-blog.csdnimg.cn/blog_migrate/0e21df7f54007eb83da7f1b7d4257da8.png)
Redux最主要是用作应用状态的管理。简言之,Redux用一个单独的常量状态树(state对象)保存这一整个应用的状态,这个对象不能直接被改变。当一些数据变化了,一个新的对象就会被创建(使用actions和reducers),这样就可以进行数据追踪,实现时光旅行。
![](https://i-blog.csdnimg.cn/blog_migrate/080949af6fc85a9cf8d9612e1a3fc2df.png)
与react绑定后使用redux实现案例
![](https://i-blog.csdnimg.cn/blog_migrate/1e5ba367050dc315bad33dec58cab88f.png)
![](https://i-blog.csdnimg.cn/blog_migrate/0b8a7ee27f17be4af4c506c9cb38ac2b.png)
![](https://i-blog.csdnimg.cn/blog_migrate/51f4f1e31335b5592d3d8f6e6462d17e.png)
![](https://i-blog.csdnimg.cn/blog_migrate/bf139ff16ecaf2ee037724f74e196d51.png)
![](https://i-blog.csdnimg.cn/blog_migrate/f1dfb11e7cc49ef0eeb76cfca6c23bd6.png)
![](https://i-blog.csdnimg.cn/blog_migrate/5ea4aea533d7795f2b073679624eb37b.png)
![](https://i-blog.csdnimg.cn/blog_migrate/c29d2645f51900774f320e71f1326561.png)
redux介绍及设计和使用的三大原则
![](https://i-blog.csdnimg.cn/blog_migrate/6c73587041f83e1b28b221704159af65.png)
![](https://i-blog.csdnimg.cn/blog_migrate/a6c265870d0ae6dfe8b2b2246cc0b92f.png)
redux工作流
![](https://i-blog.csdnimg.cn/blog_migrate/94ec247ad204ef1ad4f583927238f2b5.png)
redux原理解析
![](https://i-blog.csdnimg.cn/blog_migrate/3ee14ca54953e38a7d9a26550117b09e.png)
Redux-reducer合并
如果不同的action所处理的属性之间没有联系,我们可以把 Reducer 函数拆分。不同的函数
负责处理不同属性,最终把它们合并成一个大的 Reducer 即可。
![](https://i-blog.csdnimg.cn/blog_migrate/80becf22fc671951027bfb1b69d994bc.png)
redux中间件(异步的时候才需要)
在redux里,action仅仅是携带了数据的普通js对象。action creator返回的值是这个action类型的
对象。然后通过store.dispatch()进行分发。同步的情况下一切都很完美,但是reducer无法处理异
步的情况。
那么我们就需要在action和reducer中间架起一座桥梁来处理异步。这就是middleware。
![](https://i-blog.csdnimg.cn/blog_migrate/ef8181ecae2325e832ababe0e68a37cf.png)
![](https://i-blog.csdnimg.cn/blog_migrate/b591b594dd11fd8f0f48091278b5b0d7.png)
a.中间件的由来与原理、机制
![](https://i-blog.csdnimg.cn/blog_migrate/56b22fead8c2e5c7abe31e022f1eafc9.png)
这段代码的意思是,中间件这个桥梁接受到的参数action,如果不是function则和过去一样直接执
行next方法(下一步处理),相当于中间件没有做任何事。如果action是function,则先执行action,
action的处理结束之后,再在action的内部调用dispatch。
b.中间件-redux-thunk
redux-thunk (store.dispatch参数可以是一个function)
![](https://i-blog.csdnimg.cn/blog_migrate/4d2a82c0f5acbb80000a884e1e5a9820.png)
![](https://i-blog.csdnimg.cn/blog_migrate/f8e45a8270702a54a287276fc8d1633d.png)
![](https://i-blog.csdnimg.cn/blog_migrate/df07735556376486409f3469b7a02964.png)
![](https://i-blog.csdnimg.cn/blog_migrate/b35be32ab02aa58100b08e13202ee9f9.png)
![](https://i-blog.csdnimg.cn/blog_migrate/fad2e314edce840705eb31ecc9cba4a9.png)
![](https://i-blog.csdnimg.cn/blog_migrate/d4af15a2d3fcfed4a8596a86feee1a6d.png)
c.中间件redux-promise (store.dispatch参数可以是一个promise对象)
![](https://i-blog.csdnimg.cn/blog_migrate/677266be9987f4f65e7df0270c8a42b0.png)
![](https://i-blog.csdnimg.cn/blog_migrate/b8c3c9b8d6684af93c1054d7894b03a5.png)
![](https://i-blog.csdnimg.cn/blog_migrate/02638b60005c4a9520d400be09fb0134.png)
![](https://i-blog.csdnimg.cn/blog_migrate/9134697b45781028a507bb4a7b8d5a92.png)
Redux DevTools Extension
https://github.com/zalmoxisus/redux-devtools-extension
![](https://i-blog.csdnimg.cn/blog_migrate/c638dc40c093967ae902071c148f1d30.png)
配置store.js
![](https://i-blog.csdnimg.cn/blog_migrate/6f886661616328a15bdca08e208b7120.png)
十四. react-redux
介绍
https://github.com/reactjs/react-redux
不需要自己dispatch,connect负责包装,订阅,取消订阅
![](https://i-blog.csdnimg.cn/blog_migrate/b998f5eed152d8f3dc678e20b96f4015.png)
![](https://i-blog.csdnimg.cn/blog_migrate/5ef7a41d0336dc68ba1c641b46cf821d.png)
![](https://i-blog.csdnimg.cn/blog_migrate/ef6a087bb38ec22b29ab64d112ad7534.png)
将store存储的内容共享给App组件
![](https://i-blog.csdnimg.cn/blog_migrate/9442a6edd02ff20c71b87bac723ee3f6.png)
将store中的内容通过参数传递给App组件
![](https://i-blog.csdnimg.cn/blog_migrate/8d91e236b1b92dbc9117538ced1e4127.png)
容器组件与UI组件
(1)UI组件
•只负责 UI 的呈现,不带有任何业务逻辑
•没有状态(即不使用this.state这个变量)
•所有数据都由参数(this.props)提供
•不使用任何 Redux 的 API
(2) 容器组件
•负责管理数据和业务逻辑,不负责 UI 的呈现
•带有内部状态
•使用 Redux 的 API
Provider与connect
(1)React-Redux 提供Provider组件,可以让容器组件拿到state。
![](https://i-blog.csdnimg.cn/blog_migrate/4e666a636695e587efabf3bf08157931.png)
(2)React-Redux 提供connect方法,用于从 UI 组件生成容器组件。connect的意思,就是将这
两种组件连起来.
![](https://i-blog.csdnimg.cn/blog_migrate/d3a2685f2b64c58171294c2a3fb0e16e.png)
HOC与context通信在react-redux底层中的应用
(1) connect 是HOC, 高阶组件
(2) Provider组件,可以让容器组件拿到state , 使用了context
高阶组件构建与应用
HOC不仅仅是一个方法,确切说应该是一个组件工厂,获取低阶组件,生成高阶组件。
(1)代码复用,代码模块化
(2)增删改props
(3) 渲染劫持
![](https://i-blog.csdnimg.cn/blog_migrate/1e4b8879d8eb1b7294128cf84b637b86.png)
封装成高阶组件
![](https://i-blog.csdnimg.cn/blog_migrate/5590d588db0b38aafe843c51b94d03c1.png)
Redux 持久化
![](https://i-blog.csdnimg.cn/blog_migrate/ca72b58efc23314dfb41e9b285992101.png)
![](https://i-blog.csdnimg.cn/blog_migrate/e1f84d553081226898611516fb112683.png)
![](https://i-blog.csdnimg.cn/blog_migrate/6328ba84c598331dcd258df77eb21e69.png)
![](https://i-blog.csdnimg.cn/blog_migrate/3c6e4bc5ccd8bb29ceaa81f7a7f7c75b.png)
![](https://i-blog.csdnimg.cn/blog_migrate/e876bdd3b19a29a44b04e3fc863c3414.png)
![](https://i-blog.csdnimg.cn/blog_migrate/f0219ee117d659a763585be5d22afb9d.png)
![](https://i-blog.csdnimg.cn/blog_migrate/757d3e1b0e99a1c47d39a780c7938e43.png)
白名单:持久化;黑名单:不会持久化。
十五.UI组件库
Ant Design 是一个致力于提升『用户』和『设计者』使用体验的设计语言 ;旨在统一中台项目的前端 UI 设计,屏蔽不必要的设计差异和实现成本,解放设计和前端的研发资源; 包含很多设计原则和配套的组件库。
1. ant-design (PC端)
https://ant-design.gitee.io/index-cn (镜像库,快)
2. antd-mobile (移动端)
十六. Immutable
1.Immutable.js介绍
https://github.com/immutable-js/immutable-js
每次修改一个 Immutable 对象时都会创建一个新的不可变的对象,在新对象上操作并不会影响到原对象的数据。
![](https://i-blog.csdnimg.cn/blog_migrate/0b1e553e8cfd4d24da13617b72b6ef21.png)
2. 深拷贝与浅拷贝的关系
(1) var arr = { } ; arr2 = arr ;
(2) Object.assign() 只是一级属性复制,比浅拷贝多拷贝了一层而已。
(3) const obj1 = JSON.parse(JSON.stringify(obj)); 数组,对象都好用的方法(缺点: 不能有undefined)
3. Immutable优化性能的方式
Immutable 实现的原理是 Persistent Data Structure(持久化数据结构),也就是使用旧数据创建新数据时,要保证旧数据同时可用且不变。同时为了避免 deepCopy 把所有节点都复制一遍带来的性能损耗,Immutable 使用了 Structural Sharing(结构共享),即如果对象树中一个节点发生变化,只修改这个节点和受它影响的父节点,其它节点则进行共享。
https://upload-images.jianshu.io/upload_images/2165169-cebb05bca02f1772
4.Immutable中常用类型(Map,List)
(1)Map
第一种方法:
![](https://i-blog.csdnimg.cn/blog_migrate/df94c6a1f78acbae68b7174c87f85134.png)
![](https://i-blog.csdnimg.cn/blog_migrate/5bc83dcfa362d46be1a848de9d701c80.png)
![](https://i-blog.csdnimg.cn/blog_migrate/546319290e4407aa1b0018798c48a9a6.png)
![](https://i-blog.csdnimg.cn/blog_migrate/e9d825803cdae445fe94cec555b67b0b.png)
![](https://i-blog.csdnimg.cn/blog_migrate/b74b08f64bbbfcc7c1d36c8abc983873.png)
第二种方法:
![](https://i-blog.csdnimg.cn/blog_migrate/929b9658e23ed783c2fb66e48222c763.png)
![](https://i-blog.csdnimg.cn/blog_migrate/29ac749863ebafc3b0a3f476015e8767.png)
注意:
![](https://i-blog.csdnimg.cn/blog_migrate/681fd669ed8f8b76b5c81420d4dbd66c.png)
(2)List
普通数组的方法都可以使用
![](https://i-blog.csdnimg.cn/blog_migrate/8a8468c670dd5f18ae4b77a638fd5f72.png)
(3)fromJS
如果取一级属性 直接通过get方法,如果取多级属性 getIn(["a","b","c"]])
updateIn=>更新
![](https://i-blog.csdnimg.cn/blog_migrate/36ea233759e7bd7404e3ae6e42abdbb1.png)
![](https://i-blog.csdnimg.cn/blog_migrate/9554c1a9ed4eaea74b5652f609b2d92b.png)
![](https://i-blog.csdnimg.cn/blog_migrate/5fd3c58afb4f053e735846683c42e377.png)
5. Immutable+Redux的开发方式
![](https://i-blog.csdnimg.cn/blog_migrate/a8c88bc7ffa3c6089f9dab72ce2d5508.png)
![](https://i-blog.csdnimg.cn/blog_migrate/51ce66f456fc28429ba1c01d3d66c049.png)
6. 缺点
容易跟原生混淆
文档与调试不方便
十七.Mobx
Mobx介绍
(1) Mobx是一个功能强大,上手非常容易的状态管理工具。
(2) Mobx背后的哲学很简单: 任何源自应用状态的东西都应该自动地获得。
(3) Mobx利用getter和setter来收集组件的数据依赖关系,从而在数据发生变化的时候精确知道哪些组件需要重绘,在界面的规模变大的时候,往往会有很多细粒度更新。(vue类似)
![](https://i-blog.csdnimg.cn/blog_migrate/493bc93d7e922218abd0721582c189b4.png)
![](https://i-blog.csdnimg.cn/blog_migrate/f8d234fbada145c6a0e78c848e605bd7.png)
Mobx与redux的区别
Mobx写法上更偏向于OOP
对一份数据直接进行修改操作,不需要始终返回一个新的数据
并非单一store,可以多store。
Redux默认以JavaScript原生对象形式存储数据,而Mobx使用可观察对象
优点:
a. 学习成本小
b. 面向对象编程, 而且对 TS 友好
缺点:
a. 过于自由:Mobx提供的约定及模版代码很少,代码编写很自由,如果不做一些约定,比较容易导致团队代码风格不统一,
b. 相关的中间件很少,逻辑层业务整合是问题。
Mobx的使用
(1)observable 和 autorun
![](https://i-blog.csdnimg.cn/blog_migrate/81c8e6f7d980c3ccf7c99b9478b83bcc.png)
![](https://i-blog.csdnimg.cn/blog_migrate/4e1db4602f31bc4eb4e879ac8dae8c57.png)
![](https://i-blog.csdnimg.cn/blog_migrate/2b0b3ca70ed55f777781ef992f01f1e1.png)
![](https://i-blog.csdnimg.cn/blog_migrate/dd02c40157341ba42ea9e5c00c447b3d.png)
(2) action,runInAction和严格模式
![](https://i-blog.csdnimg.cn/blog_migrate/cc97fffc936753b28990ce202169b28b.png)
![](https://i-blog.csdnimg.cn/blog_migrate/b921b2c867c115ceda242291422e0a8d.png)
![](https://i-blog.csdnimg.cn/blog_migrate/b9aecbe9d1710645e07dd0034df40707.png)
![](https://i-blog.csdnimg.cn/blog_migrate/7594c3f5ed95b9bcb769087345522df9.png)
![](https://i-blog.csdnimg.cn/blog_migrate/34ef5d2aba0e46683cb9f0fceeadddd0.png)
mobx-react的使用
![](https://i-blog.csdnimg.cn/blog_migrate/e07a9d0d2117a8617d53c9d30e5d931c.png)
(1)react 组件里使用 @observer
observer 函数/装饰器可以用来将 React 组件转变成响应式组件。
(2) 可观察的局部组件状态
@observable 装饰器在React组件上引入可观察属性。而不需要通过 React 的冗长和强制性的 setState 机制来管理。
![](https://i-blog.csdnimg.cn/blog_migrate/493add066f3a4163790ede4840857842.png)
![](https://i-blog.csdnimg.cn/blog_migrate/79f4fd2f6ee97557b9c3a21e6d0c2e2b.png)
(3)Provider 组件
它使用了 React 的上下文(context)机制,可以用来向下传递 stores。 要连接到这些 stores,需要传递一个 stores名称的列表给 inject,这使得 stores 可以作为组件的 props 使用。this.props
![](https://i-blog.csdnimg.cn/blog_migrate/203ccd304a950fe09d6f35ba8f7cc56e.png)
![](https://i-blog.csdnimg.cn/blog_migrate/2e7a9ecf977336d7af913854ffed4035.png)
5. 支持装饰器
npm i @babel/core @babel/plugin-proposal-decorators @babel/preset-env
创建 .babelrc
![](https://i-blog.csdnimg.cn/blog_migrate/e4d2ef104bb781b2fd5c015d1dc72872.png)
创建config-overrides.js
![](https://i-blog.csdnimg.cn/blog_migrate/186e2f008188a6b1c025f3c504c50c5a.png)
安装依赖
npm i customize-cra react-app-rewired
修改package.json
![](https://i-blog.csdnimg.cn/blog_migrate/5b8273e28bc3d8839a052ecb58912555.png)
十八.TS
typescript
https://zhongsp.gitbooks.io/typescript-handbook/content/doc/handbook/
(1) TypeScript 的定位是静态类型语言,在写代码阶段就能检查错误,而非运行阶段
(2) 类型系统是最好的文档,增加了代码的可读性和可维护性。
(3) 有一定的学习成本,需要理解接口(Interfaces)、泛型(Generics)、类(Classes)等
(4) ts最后被编译成js
安装
![](https://i-blog.csdnimg.cn/blog_migrate/f00109079fbd5d81934b0c4f497bf059.png)
变量声明
基本数据类型
![](https://i-blog.csdnimg.cn/blog_migrate/566b0b9fee2adc6e122c75d69abda655.png)
![](https://i-blog.csdnimg.cn/blog_migrate/e8d12f9a2ae093c7a1e79a95393b33f1.png)
数组
![](https://i-blog.csdnimg.cn/blog_migrate/e021dde3f64b21828c3c6d99d1c5cb9b.png)
![](https://i-blog.csdnimg.cn/blog_migrate/5a7e93058dcd446022180ef2b6ddb66d.png)
对象
![](https://i-blog.csdnimg.cn/blog_migrate/af4ee403e4da48664bbf939875c6a206.png)
![](https://i-blog.csdnimg.cn/blog_migrate/9c0ebd07347b1a5fa772f90bca16daf2.png)
![](https://i-blog.csdnimg.cn/blog_migrate/0221af01cfb2871cc383556f34b0f514.png)
函数
![](https://i-blog.csdnimg.cn/blog_migrate/c199129e94947e94bbc3289dd72e3baf.png)
![](https://i-blog.csdnimg.cn/blog_migrate/add51b9ec580749211a87fc6d6784caf.png)
![](https://i-blog.csdnimg.cn/blog_migrate/34d7a3f624022cb492063d85cf372c2e.png)
![](https://i-blog.csdnimg.cn/blog_migrate/6aa62330adf37e4cfa74248c4a241f40.png)
![](https://i-blog.csdnimg.cn/blog_migrate/d53fbd90db027bbff18faee40eb4a15a.png)
类
![](https://i-blog.csdnimg.cn/blog_migrate/6dfa041dde6adc787272bd5651b43f28.png)
类+接口
![](https://i-blog.csdnimg.cn/blog_migrate/cca21842b46797f50ef5b6359083bb3c.png)
![](https://i-blog.csdnimg.cn/blog_migrate/ff0279f6ab62a54f17fcc3cad21d5a65.png)
![](https://i-blog.csdnimg.cn/blog_migrate/9475af5520c4feedc9feda53724a3186.png)
函数组件
![](https://i-blog.csdnimg.cn/blog_migrate/b53137dab44739bc72bc934ebf5b60c9.png)
![](https://i-blog.csdnimg.cn/blog_migrate/5edce80105b84d704e7a5e3a25450f0c.png)
![](https://i-blog.csdnimg.cn/blog_migrate/81503da7f6d7193afab5affc8788698f.png)
十九.styled-components
![](https://i-blog.csdnimg.cn/blog_migrate/6d8fe4cd987c702645b9703041e3c88e.png)
二十.单元测试
![](https://i-blog.csdnimg.cn/blog_migrate/0e600854233a973968eb50bfe224100e.png)
![](https://i-blog.csdnimg.cn/blog_migrate/c5b1b310023779c315f7d765b7e64af7.png)
![](https://i-blog.csdnimg.cn/blog_migrate/546301f66438634f705e15bd4799673a.png)
![](https://i-blog.csdnimg.cn/blog_migrate/0facbdd280851d46c9f3ffa58a53c092.png)
![](https://i-blog.csdnimg.cn/blog_migrate/d50e868cfd12a5b421c0cfd6ece19310.png)
![](https://i-blog.csdnimg.cn/blog_migrate/4814f245b1fb75c3c7e33209a3db5084.png)
![](https://i-blog.csdnimg.cn/blog_migrate/0d77fda751203cbf6515da86864723c0.png)
二十一.redux-saga
生成器
![](https://i-blog.csdnimg.cn/blog_migrate/24fe9a0cb30288b2bc60b3270c2bf152.png)
![](https://i-blog.csdnimg.cn/blog_migrate/a0e6b7a84c7bb8c8809c18e65747efcb.png)
![](https://i-blog.csdnimg.cn/blog_migrate/0b5f30714269a2a6c2d2f04496ee5ac3.png)
![](https://i-blog.csdnimg.cn/blog_migrate/50c15ada61a2d05587b9463785fc6062.png)
![](https://i-blog.csdnimg.cn/blog_migrate/047c093a893939158a240cbc5cb05fe4.png)
可执行生成器
异步流程
![](https://i-blog.csdnimg.cn/blog_migrate/36d49a80767bd60fde7d7825ac280735.png)
![](https://i-blog.csdnimg.cn/blog_migrate/6c1d73f611e9af837c381e26467d9f17.png)
![](https://i-blog.csdnimg.cn/blog_migrate/61b598ac8be9c5c3bcac91872f795929.png)
![](https://i-blog.csdnimg.cn/blog_migrate/2a8c14cab2e49689e11ccfe120d16220.png)
二十二.react-router 6
概述
(1)官方文档:Home v6.4.1 | React Router
(2)
react-router: 路由的核心库,提供了很多的组件、钩子。
react-router-dom: 包含react-router所有内容,并添加一些专门用于 DOM 的组件,例如 <BrowserRouter>等 。
react-router-native: 包括react-router所有内容,并添加一些专门用于ReactNative的API,例如:<NativeRouter>等。
(3)
a.与React Router 5.x 版本相比,改变了什么?
b.内置组件的变化:移除<Switch/> ,新增 <Routes/>等。
c.语法的变化:component={About} 变为 element={<About/>}等。
d新增多个hook:useParams、useNavigate、useMatch等。
e.官方明确推荐函数式组件了!!!
(4)安装
npm install react-router-dom@6
BrowserRouter和HashRouter
(1)在 React Router 中,最外层的 API 通常就是用 BrowserRouter。BrowserRouter 的内部实现是用了 history 这个库和 React Context 来实现的,所以当你的用户前进后退时,history 这个库会记住用户的历史记录,这样需要跳转时可以直接操作。
(2)BrowserRouter 使用时,通常用来包住其它需要路由的组件,所以通常会需要在你的应用的最外层用它。
![](https://i-blog.csdnimg.cn/blog_migrate/976246b9a2dddc3dbf66aeacfa92e7a2.png)
(3)HashRouter:作用与<BrowserRouter>一样,但<HashRouter>修改的是地址栏的hash值,
6.x版本中<HashRouter>、<BrowserRouter> 的用法与 5.x 相同。
Routes 与 Route
a.v6版本中移出了先前的<Switch>,引入了新的替代者:<Routes>。
b.<Routes> 和 <Route>要配合使用,且必须要用<Routes>包裹<Route>。
c.<Route> 相当于一个 if 语句,如果其路径与当前 URL 匹配,则呈现其对应的组件。
d.<Route caseSensitive> 属性用于指定:匹配时是否区分大小写(默认为 false)。
e.当URL发生变化时,<Routes> 都会查看其所有子 <Route> 元素以找到最佳匹配并呈现组件 。
f.<Route> 也可以嵌套使用,且可配合useRoutes()配置 “路由表” ,但需要通过 <Outlet> 组件来渲染其子路由。
(1)Route
Route 用来定义一个访问路径与 React 组件之间的关系。比如说,如果你希望用户访问 https://your_site.com/about 的时候加载 <About /> 这个 React 页面,那么你就需要用 Route:
<Route path="/about" element={<About/>}/>
![](https://i-blog.csdnimg.cn/blog_migrate/b391a19483d4dec2403205a6bd4b47c2.png)
(2)Routes
Routes 是用来包住路由访问路径(Route)的。它决定用户在浏览器中输入的路径到对应加载什么 React 组件,因此绝大多数情况下,Routes 的唯一作用是用来包住一系列的 Route。
![](https://i-blog.csdnimg.cn/blog_migrate/7adbf2246f70b6ca9c967f62a66eb2ff.png)
![](https://i-blog.csdnimg.cn/blog_migrate/1f91da9db592a70e541086295ef47d78.png)
(3)例子
![](https://i-blog.csdnimg.cn/blog_migrate/97fe520c660d719e46dccf1395abe288.png)
设置默认页路径(如 404 页)
(1)在最后加入 path 为 * 的一个路径,意为匹配所有路径。
![](https://i-blog.csdnimg.cn/blog_migrate/5620176526009011dbcb19261dd9181b.png)
Link
(1)作用: 修改URL,且不发送网络请求(路由链接)。
(2)注意: 外侧需要用<BrowserRouter>或<HashRouter>包裹。
![](https://i-blog.csdnimg.cn/blog_migrate/211bc9b8fbbd00d66aa151f7a84c649e.png)
NavLink
(1)作用: 与<Link>组件类似,且可实现导航的“高亮”效果。
![](https://i-blog.csdnimg.cn/blog_migrate/6e8ae5db6c3c379e41e9b2271a2a33e9.png)
Navigate
(1)作用:只要<Navigate>组件被渲染,就会修改路径,切换视图。
(2)replace属性用于控制跳转模式(push 或 replace,默认是push)。
(3)相当于5版本的Redirect。
![](https://i-blog.csdnimg.cn/blog_migrate/a69206d005ece558631f77417bd8f7ea.png)
(4)跳转模式
![](https://i-blog.csdnimg.cn/blog_migrate/dc3b70b32d10f5e556fb47a6415db895.png)
使用useRoutes注册路由
(1)src文件夹下新建子文件夹:routes,routes下新建文件:index.js 路由表独立成js文件:src/routes/index.js
routes/index.js
![](https://i-blog.csdnimg.cn/blog_migrate/5fa3fb1c9367072b495f28b830f1d919.png)
App.js
![](https://i-blog.csdnimg.cn/blog_migrate/4cc94cfa13ee0ee82ba1080a11f4a048.png)
嵌套路由的实现
(1)routes/index.js,用 children 来嵌套路由。
![](https://i-blog.csdnimg.cn/blog_migrate/db2ddad7c5d15b67557de372f03ab8fa.png)
(2)Home/index.js,<Outlet>
作用:当<Route>产生嵌套时,渲染其对应的后续子路由。
![](https://i-blog.csdnimg.cn/blog_migrate/ce7bb027773899c41239f9bc33c9460c.png)
路由链接中的 to 属性值,可以是
to="/home/news",即全路径(推荐这样写,不然直接看不知道是不是子路由)
to="./news",即相对路径
to="news"
获取params参数有两种方式:
(1)使用 useParams
const {id,title,content} = useParams();
(2)使用 useMatch
const {params:{id,title,content}}=useMatch("/home/message/detail/:id/:title/:content");
![](https://i-blog.csdnimg.cn/blog_migrate/53225a6caddcdc04129b1e01f9f9ca7f.png)
![](https://i-blog.csdnimg.cn/blog_migrate/ed9b068565e5f84fd5e8391f704be7b8.png)
传递 search 参数
(1).useSearchParams()
作用:用于读取和修改当前位置的 URL 中的查询字符串。 返回一个包含两个值的数组,内容分别为:当前的seaech参数、更新search的函数。
(2).useLocation()
作用:获取当前 location 信息,对标5.x中的路由组件的location属性。
![](https://i-blog.csdnimg.cn/blog_migrate/970da900af15b1f45e2f64a8e9322a09.png)
![](https://i-blog.csdnimg.cn/blog_migrate/c3780c870e59615ebc31a448f266adb1.png)
(3).使用useLocation
记得下载安装qs:npm install --save qs。
nodejs官方说明querystring这个模块即将被废弃,推荐我们使用qs模块
![](https://i-blog.csdnimg.cn/blog_migrate/50676668f80fd5ddd40267d8b94322a1.png)
传递 state 参数
![](https://i-blog.csdnimg.cn/blog_migrate/5209c3b7784dc5e89aa7c70586f05ca1.png)
![](https://i-blog.csdnimg.cn/blog_migrate/ce92a37bbb59439e3cb05ced20588ad7.png)
刷新页面后对路由state参数的影响 :
在以前版本中,BrowserRouter没有任何影响,因为state保存在history对象中;HashRouter刷新后会导致路由state参数的丢失 但在V6版本中,HashRouter在页面刷新后不会导致路由state参数的丢失。
13.编程式路由导航
(1) 编程式导航下,路由传递params参数
![](https://i-blog.csdnimg.cn/blog_migrate/e8124b360d7e9fd125a4fd36492df94f.png)
![](https://i-blog.csdnimg.cn/blog_migrate/2792a2a532e964fff3918466398d2a6c.png)
(2)编程式导航下,路由传递search参数
![](https://i-blog.csdnimg.cn/blog_migrate/26bc45acf84df066b294944864e8cebc.png)
![](https://i-blog.csdnimg.cn/blog_migrate/2a748a61fd7c78b9dc0647a5e4dcd8af.png)
(3)编程式导航下,路由传递state参数
![](https://i-blog.csdnimg.cn/blog_migrate/1e736d26125bc91888c8c4a21e248414.png)
![](https://i-blog.csdnimg.cn/blog_migrate/3e18f46f11ec6750837a98071eb52e2c.png)
(4)withRouter的替换者
我们可以利用 react-router-dom 对象下的 withRouter 函数来对我们导出的 Header 组件进行包装,这样我们就能获得一个拥有 history 对象的一般组件。
withRouter可以加工一般组件(即非路由组件),让一般组件具备路由组件所持有的API。但v6版本中已废除,可以直接用useNavigate实现。
![](https://i-blog.csdnimg.cn/blog_migrate/b04db092e77c3464b6ebb2d511ed8fc7.png)
参考链接:
https://github.com/dselegent/Learning-Notes/tree/master/react