React笔记

1.React是什么:

用于构建用户界面的JavaScript库

1.1 特点

采用组件化模式,声明式编码,提高开发效率和组件复用率
在react Native里可以使用React进行移动端开发(可以用js的语法写安卓和ios应用!!)
使用了虚拟dom以及优秀的diffing算法,减少了与真实dom 的交互

1.2 jsx:

全称叫JavaScript XML,用来解决使用js创建虚拟dom过于繁琐的问题
它是react定义的一种类似于XML的js扩展语法
语法规则:
1.定义虚拟dom的时候不能写引号。
2.如果想要使用js的语法,必须写{ }

3.创建虚拟Dom时候,如果想要在虚拟DOM节点上写类名,则class属性要写成className。(防止与es6中类的关键词冲突)
在这里插入图片描述
4.写内联样式的时候要写双大括号,并且值要写成字符串的形式
在这里插入图片描述
当写fontsize这种样式的时候,要写小驼峰的形式。
在这里插入图片描述
5.必须且只能有一个根标签;标签必须闭合,单标签也必须闭合,比如input
6.关于标签首字母:如果是小写字母开头,则将其转为html同名标签;大写字母开头的则为组件。
在这里插入图片描述

1.3关于虚拟dom

本质上是object类型的对象
比起真实DOM,它更轻量级,因为它是React自身在使用,无需太多属性

2.React组件化开发

2.1函数式组件

定义一个函数,由函数返回一个 虚拟DOM
在这里插入图片描述
使用ReactDom.render渲染组件到页面
在这里插入图片描述
react解析组件标签,找到demo组件;发现组件是由函数定义的,随后调用该函数,将返回的虚拟DOM转为真实DOM

2.2类式组件开发

如果使用类定义一个组件,必须遵循以下规则:

  1. 该类必须继承React的一个内置类:React.Component

  2. 类中必须定义render方法,且render返回(该render函数放在类的原型对象上,供实例使用)

之后执行ReactDOM的render方法
在这里插入图片描述
当执行该方法后,React解析组件标签 ,找到MyComponent组件,发现组件是由类定义的,则随后new一个该类的实例,并通过该实例调用到原型上的render方法,然后将render返回的虚拟DOM转为真实DOM渲染到页面。

2.2.1

类组件中render方法中的this,指向该类的实例对象。

在这里插入图片描述

2.3 复杂组件和简单组件

如果组件内有状态(state)就是复杂组件。

2.3.1 组件实例的三大属性之一:state状态

使用方法:在类定义的组件中,在定义时候写构造函数,在构造函数中接收props,因为继承了其他类并且写了构造函数所以必须调用super。state必须是一个对象。
在这里插入图片描述
React中的事件绑定:将原生的事件重写了,比如οnclick=>onClick
在这里插入图片描述
需要注意的是,这里的onClick后的函数表达式不能写小括号,因为代码在渲染组件到页面的时候,它会执行redner函数,然后当执行到return语句的时候,如果你写了demo(),那么旧相当于把函数的返回结构赋值给了onClick所以此时点击也不会生效,而不是将该函数赋值给onClick

通过绑定该h2的点击事件修改state的值:首先,state中的数据不允许直接更改,需要使用内置的setState方法,每次修改状态,都会调用类中的render方法。
在这里插入图片描述
简写方法
在这里插入图片描述

2.3.2 组件实例的三大属性之一:props

每个组件对象都会有props属性;组件标签的所有属性都存在props中
用于给组件传递数据
使用方法:在使用ReactDOM.render渲染组件到页面的时候,通过属性方式传递
在这里插入图片描述
批量传递:
在这里插入图片描述
关于这个展开运算符,原本它不能用来展开一个对象,因为这里使用了babel和react的缘故,所以才能起效果,在原生js中,直接使用…展开一个对象会报错。在es语法中,规定使用{…对象}的语法,可以展开一个对象。并且使用这种形式可以实现深拷贝
之后可以在类组件的内部使用,比如在render函数中可以使用this.props.xxx调用到。

对props进行限制:

在react版本为15.xxx的时候,可以直接使用这种方法,因为里面有一个内置的React.PropsTypes.string,用来限制属性的数据类型

在这里插入图片描述
表示name属性的数据类型为string

但是在react16.xxx版本中,这种方法被废弃了,因为这个React属性非常核心,加这个属性会显得臃肿。并且有时候并不会用到规定数据类型。
新的写法:使用资料中的依赖包prop-types.js
引入该js文件后,就会多出来一个全局对象Prop-types
在这里插入图片描述
需要注意的是,如果需要限制某个属性的数据类型是函数的话,应该写PropTypes.func

限制某个属性必须传递,不传递则报错

只需要在PropType.string.isRequired,表示该属性必传并且只能是字符串

限制某个属性的默认值(当不传的时候有默认值)

使用 类名.defaultProps={属性名:属性值}
在这里插入图片描述
简写方法,直接写在类里面
在这里插入图片描述
static关键字表示静态属性,对static标记的方法和属性只属于类,不属于实例对象 。静态方法调用直接在类上进行,不能在类的实例上调用。静态方法通常用于创建实用程序函数。

类式组件中的构造器:
在这里插入图片描述
意思就是,类中的构造器是可以省略的,如果你没有省略,那么必须在里面调用super并且接收props,给super传入props,目的是为了防止你在构造器中使用props时出现undefined的情况。

函数式组件使用props

它不能使用refs和state,因为没有实例,但是可以使用props因为它可以接收参数。所有你在使用ReactDOM.render时候在标签里传入的自定义属性都会变成函数的参数
在这里插入图片描述
这里的函数的形参props就是
在这里插入图片描述
同时也可以对函数的参数做出限制,但是必须写在函数体外部

2.3.3 组件实例的三大属性之一:refs

标签加上ref属性,通过refs获取到该节点,类似于id属性
在这里插入图片描述
但是这种字符串形式的ref已经不被官方推荐使用了
在这里插入图片描述
主要是效率上的问题。
现在官方推荐使用回调的ref,写法就是在标签里写ref的时候写成回调函数
在这里插入图片描述
该函数会有一个参数,就是当前ref所在的节点
在这里插入图片描述
表示在实例自身上加了一个input1的属性,指向该node节点
在这里插入图片描述
关于回调ref的说明
在这里插入图片描述
内联的方式就是说在标签中写的。
比如当你页面上需要用到state中的数据的时候,刚好你有一个按钮可以修改state中的内容,然后当你修改state的内容时候,就会引起页面的更新,就会重新调用一次类中的render函数,render函数中你的ref写的是内联状态的回调ref,由于它不确定之前的函数中做了什么操作,为了保证新的页面中使用到新的回调函数,就会调用一次并且传入null,所以传null的这一次就相当于一次清空的动作,在这之后才会传入真正的DOM节点。
解决方法:类绑定函数的形式(就是将回调函数写在类实例的自身上)在这里插入图片描述
使用createRef
使用方法:React.createRef()是一个函数,调用后返回一个容器,该容器可以存储被ref所标识的节点
首先,在实例上定义一个变量myRef=React.createRef(),相当于先创建一个容器
然后在标签里的ref属性中的值为{this.myRef},相当于把该标签节点装进容器内
这时候它就会将该节点存入myRef中
在这里插入图片描述
这时候就可以通过this.myRef.current.value拿到输入框的值
注意,一个容器只能存一个节点,也就是说,在你定义了一个容器后,只能给一个节点的ref属性使用。

2.4.React中的事件处理

2.4.1通过onXXX指定事件处理函数(注意大小写)

a.React使用的是自定义事件,而不是原生的DOM事件,比如onclick事件React是onClick --为了更好的兼容性
b.React中的事件是通过事件委托方式处理的(委托给组件最外层)--为了高效率

2.4.2 通过event.target得到发生事件的DOM元素对象

当你在标签中指定了事件,比如onClick并且值是一个回调函数的时候,该回调函数中react会给它传入一个参数event,可以通过event.target拿到该元素

在这里插入图片描述

2.5.收集表单数据

2.5.1包含表单的组件分类

a.受控组件:当页面中的输入DOM,随着输入内容,它能够自动将数据放入state中,需要用的时候直接从state中取,就叫受控组件
b.非受控组件:表单内所有输入类DOM的值,如input,checkbox,radio,如果你是现用现取,那么就是非受控组件,比如你定义了一个input,然后又定义一个按钮,当点击按钮后就取input里的值。

2.6 高阶函数与函数柯里化

2.6.1 高阶函数

若该函数,接受的参数是一个函数或者该函数的返回值是一个函数则该函数为高阶函数

2.6.2 函数柯里化

通过函数调用继续返回函数的方式,实现多次接收参数最后统一处理的函数编码形式

2.7 组件的生命周期

挂载(mounted)
卸载(unmount)

卸载组件的API:ReactDOM.unmountComponentAtNode()参数传一个dom节点
componentDidMount(){} 类似于render函数,react会在组件挂载时调用一次
componentWillUnmouunt(){} 组件将要被卸载时调用
在这里插入图片描述

2.7.1旧版本:

在这里插入图片描述

2.7.1.1组件挂载到页面的流程:

首先调用类组件中的构造函数,然后调用componentWillMount生命周期函数,再调用render函数,然后调用componentDidMount,然后调用componentWillUnmount

2.7.1.2 使用setState方法后组件更新的流程:

1.在调用了setState之后会调用shouldComponentUpdate钩子,该钩子会返回true或者false,该钩子默认返回true,但是当你有业务需求的时候可以重写该钩子,令它返回false。如果时true,则继续走向componentWillUpdate,如果是false就不继续走。
2.componentWillUpdate
组件将要更新的钩子
3.componentDidUpdate
组件更新完毕的钩子

2.7.1.3 使用forceUpdate方法后组件更新的流程

使用setState是正常更新,而forceUpdate方法是强制更新,也就是当你不修改stste里面的数据,也想要组件更新: 它不会受到shouldComponentUpdate的限制
1componentWillUpdate
组件将要更新的钩子
2.componentDidUpdate
组件更新完毕的钩子
在这里插入图片描述

2.7.1.4 父组件render流程

如何让类组件当中形成父子关系
在这里插入图片描述
在A组件的返回的DOM结构中使用B组件标签
可以通过标签属性的形式给B组件传递内容
在这里插入图片描述
B组件中使用props来接收
在这里插入图片描述
那么这时,你在子组件B的内部写了componentWillReceiveProps钩子的话,它就会子组件接收到参数时候被调用执行
componentWillReceiveProps钩子里的坑:第一次传递的时候不会执行
在父组件render触发更新后,会调用componentWillReceiveProps方法,然后调用shouldComponentUpdate,然后componentWillUpdate,然后调用子组件的render函数,然后调用componentDidUpdate

2.7.1.5 总结

组件初次渲染:
由ReactDOM.render()触发

  1. constructor()
  2. componentWillMount()
  3. render()
  4. componentDidMount()----常用钩子,一般在这里初始化一些页面数据之类的
    更新阶段:
    由组件内部的this.setState()或者父组件的render触发
    shouldComponentUpdate()
    componentWillUpdate()
    render()
    componentDidUpdate()–它可以接收到三个个参数,第一个参数是更新前得到的props,第二个是更新前的state,第三个是snapeShotValue
    卸载阶段:
    由ReactDOM.unmountComponentAtNode()触发
    然后调用componentWillUnmount

2.7.2 新的生命周期

在这里插入图片描述
在新版的生命周期钩子中,componentWillMount,componentWillReceiveProps,componentWillUpdate三个钩子更名为需要加上UNSAFE_前缀,比如UNSAFE_componentWillMount(所有带will的钩子都需要在前面加上下划线前缀,除了componentWillUnmount)
原因:
在这里插入图片描述
挂载时:
constructor>getDerivedStateFromProps>render>react更新DOM和refs>componentDidMount

getDerivedStateFromProps:

getDerivedStateFromProps介绍:
1.当你使用它的时候,必须在前面写static关键字
2.必须有返回值,返回一个状态对象()或者为null,返回状态对象的时候,如果返回的状态对象在state中不存在,会将该状态对象放入state中;如果存在,则会覆盖原来的,并且该对象就不能再被修改了。
3.它可以接收props参数,就是你通过自定义属性给该组件传参,这里可以接收到传递的参数。
4.适用场景:在这里插入图片描述

getSnapshotBeforeUpdate:

1.必须要有返回值,可以返回null,返回值将在下一个生命周期钩子:componentDidUpdate中的第三个参数得到
它的调用时机是在render和componentDidupdate之间
在这里插入图片描述

总结:
在这里插入图片描述
重要的钩子:
在这里插入图片描述
即将废弃的钩子:
在这里插入图片描述

2.8 DOM的diffing算法

2.8.1 虚拟DOM中key的作用

简单来说,key是虚拟DOM对象的标识,在更新显示的时候起到非常重要的作用。
详细来说,当状态中的数据发生变化的时候,react会根据【新数据】生成【新的虚拟DOM】,随后react进行【新的虚拟DOM】和【旧的虚拟DOM】进行diff比较,规则如下:
1.虚拟DOM找到了和新的DOM相同的key
(1)若虚拟DOM中的内容未发生改变,则直接使用之前的真实DOM
(2)若虚拟DOM中的内容发生改变,则生成新的真实DOM,并替换掉以前的真实DOM
2.若虚拟DOM中未找到与新的虚拟DOM相同的key
根据数据创建新的虚拟DOM并渲染到页面

2.8.2 在遍历列表时,为什么key不能用index

>若对数据进行:逆序添加,逆序删除等破坏顺序的操作时候,会产生没必要的真实DOM更新,虽然界面效果没问题,但是效率极低
>如果结构中还包含输入类DOM,会产生错误的DOM更新,界面会发生错误。比如这个案例中

在这里插入图片描述

3.初始化React脚手架

reac提供了一个用于创建项目的脚手架库:create-react-app
项目整体技术架构为:react+webpack+es6+eslint
在这里插入图片描述

3.1脚手架文件介绍

public 一般放静态页面,图片等

public里面的index.html 为应用的主页面,(spa应用)
在这里插入图片描述

src文件夹中的文件:

在这里插入图片描述

样式的模块化:防止多个组件的css文件造成样式冲突
名字改为xxx.module.css比如index.css文件,首先需要将名字改成index.module.css,
然后引入方式就可以变化,之前引入css使用的是 import ‘xxx’,现在可以用一个变量 ,import 变量名 from ‘css路径’
然后在写类名的时候,直接写变量.类名
在这里插入图片描述
比如这里hello中有一个类名叫title

3.2 todolist案例:

总结:
1.input的checkbox有一个属性,defaultChecked,默认是否勾选
2.子组件传递东西给父组件:首先在父组件中定义一个箭头函数,该函数接受一个data形参,然后将该函数传给子组件,由子组件调用该函数,实参就是子组件中的数据、
3.自动生成id库:nanoid
4.限制prop的类型,需要自行下载prop-types库,然后import引入
5.更改一个对象时候,这里的…表示复制obj1里的所有内容这里是深拷贝在这里插入图片描述
6.在使用原生js 的confirm方法的时候,必须是加上window.confirm,不然会报错。且confirm自带返回值,用户点确定会返回true,取消返回false,非常方便做if判断
7.数组身上的reduce方法专门用来做条件统计,条件求和,筛选最值等的,比如统计数组中
8.动态初始化列表,如何确定将数据放在哪一个组件的state中:

如果是某个组件单独使用则放在其自身的state
如果是一堆组件需要使用,则放在其父元素中的state

9.关于父子组件的通信

父传子使用props
子传父,需要父组件给子组件传递一个函数,函数接受一个参数,子组件调用该函数,并传入参数

4.React ajax

4.1理解

4.1.1 前置说明

1.react自身只关注于界面,并不包含发送Ajax请求的代码(也就是说没有react.ajax这种东西)
2.前端应用需要通过ajax请求与后台进行交互(json数据)
3.react应用中需要集成第三方ajax库(或者自己封装)

4.2 react一般采用的ajax库:axios

axios:轻量级
封装XMLHTTPRequest对象的ajax;promise风格;可以用在浏览器端和服务器端。
需要使用npm安装,然后import引入

4.3 脚手架配置代理

4.3.1 方法一:

比如你的客户端在localHost3000,而服务器在5000端口
在package.json文件中添加proxy配置
在这里插入图片描述
然后在axios请求中,请求的地址就应该是localHost3000,而不是5000
此方法的弊端:如果请求的数据,比如你想要请求服务器上的index.html文件,而这时,因为客户端所开启的代理服务器上有index.html文件,那么它会返回客户端上的index.html文件而不会转发请求。

4.3.2 方法二:

如果想要配置多个代理:
首先在src目录下创建一个setupProxy.js文件(名字必须是固定的,且文件内容不能使用es6,必须用commonjs的规范)
在这里插入图片描述

4.4 GitHub搜索案例总结

4.4.1 关于解构赋值:连续解构赋值写法

在这里插入图片描述
相当于
const {keyWordElement} =this
const {value} =keyWordElement
解构赋值的同时重命名:
在这里插入图片描述

此时解构出来的b就是data

4.4.2 三元运算符多个判断条件

三元运算符可以连着写多个判断条件

4.5 消息订阅-发布机制

4.5.1 工具库pubsub.js

npm i pubsub-js 安装到项目,import引入

4.5.2 使用原则

在需要接受消息的组件中去订阅消息,如果有组件发布了该消息,那么该组件就会执行回调函数,该回调函数有两个参数,第一个为msg(消息名),第二个参数是data(其他组件所交给你的数据)
需要在componentWillUnmount中取消订阅
订阅:
在这里插入图片描述
发布:
在这里插入图片描述

4.6 fetch发送请求

4.6.1 特点

原生函数,不需要使用XMLHTTPRequest对象提交ajax请求
promise风格
符合关注分离的设计思想(把一个需求拆分成多个小的流程执行)
但老版本浏览器可能不支持

4.6.2 用法

在这里插入图片描述
使用catch统一处理错误
在这里插入图片描述
使用async,await优化(顶部的函数需要加上async标识),配合try,catch捕获错误

在这里插入图片描述

5. React路由

5.1 相关理解

5.1.1 SPA页面的理解

1.单页web应用
2.整个应用只有一个完整的页面
3.点击页面中的链接不会刷新页面,只会做页面的局部刷新
4.数据都需要通过ajax获取,并在前端做异步呈现

5.1.2 前端路由原理

基于BOM对象的history所工作的
浏览器的历史路径记录是一个栈结构
可以通过监听history历史记录,进行路由操作

5.2 路由的基本使用

5.2.1 react-router-dom库

1.react的插件库(需要自行安装)
2.专门用来实现一个SPA应用
3.基于react的项目都会用到这个库

5.2.2 react-router-dom的相关API

内置组件:
1.BrowserRouter
2.HashRouter
3.Route
4.Redirect
5.Link
6.NavLink
7.Switch

5.2.2.1 基本使用

Link组件
路由链接,切换组件,类似a标签
需要手动引入
在这里插入图片描述

v6版本中Link标签外需要包裹Router标签,router标签分两种,BrowserRouter和HashRouter,v5使用switch
在这里插入图片描述
Route组件
路由组件,首先需要编写路由链接(注册路由)

当路径为/home的时候展示home组件,为/about的时候展示about组件
使用方法,在这里插入图片描述
一般搭配Link使用,需要使用Routes根组件标签(原因在下面一节)包裹所有的Route且整体需要一个BrowserRoute组件标签包裹,所以,一般将BrowserRoute放在App的外面
在这里插入图片描述

5.2.2.2 路由组件特点

一般路由组件都放在pages文件夹中而不是components

路由组件中的props里默认有三个参数
在这里插入图片描述
其中常用的属性有:
在这里插入图片描述
路由链接动态追加类名(点击链接高亮效果):
需要使用一个升级版的Link标签:NavLink
需要手动引入该组件,NavLink标签有一个自带的功能,就是当你点击后,会自动追加一个active的类,该组件标签有一个属性:activeClassName,用来指定类名(默认是active)在这里插入图片描述

5.2.2.3 封装NavLink组件

当有多个导航的时候,写多个重复的NavLink属性很不方便,代码有优化空间

自定义组件时候,在使用组件标签时,通过属性传递的数据可以使用props获取,标签体内容可以通过props.children得到,同时,也可以通过children属性给标签设置标签体内容。
在这里插入图片描述
使用:
在这里插入图片描述

5.2.2.4 Routes的使用

在这里插入图片描述

当写了两个一样路径的route组件,会同时展示两个组件,home和test
这是因为,当第一个路由组件匹配到对应的路径后,他还会继续向下匹配
在这里插入图片描述比如这种情况第一个路由路径匹配home的,它在匹配了第一个后,还会一直向下找,查看是否还有匹配home路径的组件,然后一起展示,这样会造成效率的问题,很多时候我们只需要它匹配到第一个就停止匹配了。正常情况下一般都是一个组件对应一个路径。
这里就需要用到Routes组件,需要手动从react-router-dom库引入
使用方法:将所有的Route组件使用Routes包裹起来

5.2.2.5 解决样式丢失的问题

问题原因,在配置路由之后,更改后的路径可能会造成样式请求失败
解决:public文件夹下的index.html中的引入样式Link属性中使用绝对路径
在这里插入图片描述

5.2.2.6 路由重定向的使用

引入该组件,放在注册路由的最下方
react 6.0使用navigate在这里插入图片描述
此前的版本使用Redirect
在这里插入图片描述

5.2.2.7 路由嵌套

v5版本中,路径要写全
在这里插入图片描述

v6版本以后:
父级路由:路径后面必须加一个/*
在这里插入图片描述
子级路由:注册路由时不用写/home/xxx,直接写xxx就可以
在这里插入图片描述

5.2.3 路由参数传递

params(路径传参)

模板字符串拼接路径
在这里插入图片描述
注册的路由中声明
在这里插入图片描述
在子路由组件中:使用props.match.params获得传过来的params参数
在v6版本中:????

search参数:

方法:类似于ajax的query参数。需要使用?拼接
在这里插入图片描述
search参数无需声明接收,而params参数必须在注册路由的时候声明接收
在子路由组件中,使用this.props.location
在这里插入图片描述
有一个querystring库可以专门分割search参数为键值对
在这里插入图片描述
补充:key=value&key=value这种编码形式叫做urlencoded
若想将对象转为这种形式,可以借助qs.stringfy(对象)
字符串转为对象可以借助,qs.parse(str)
最后将search转为键值对的形式(截取掉第一个问号)
在这里插入图片描述
总结:
在这里插入图片描述

路由组件传递state参数*(与组件中的state状态不是同一个东西)

优势:不会在地址栏中显示
方法:在link组价标签的to属性中的值改为一个对象
在这里插入图片描述
注册路由时无需声明接收,正常注册即可。
在需要接收的路由组件中使用this.props.location.state中拿到传递的state参数。
为什么使用state传递参数,但是刷新页面后数据却不会丢失:
因为我们使用了browserRouter,它一直在操纵浏览器的history。所以当我们清除了浏览器缓存,state就会消失
**总结:
**

5.2.4 路由跳转的几种方式

push和replace
push相当于压栈的操作(先进后出)
replace替换当前路由
默认开启的是push模式,Link组件标签有一个属性可以更改
在这里插入图片描述

5.2.5 编程式路由导航

借助于路由组件中的this.props.history中的push和replace方法
携带params参数
在这里插入图片描述
携带search参数
在这里插入图片描述
携带state参数

在这里插入图片描述
其中push方法同理

前进后退页面的API:
history身上带的goForward和goBack方法
在这里插入图片描述
go方法,参数传入数字,正数表示前几几页,负数表示回退几页
总结:

在这里插入图片描述

5.2.6 withRouter的使用

使得一般组件也可以使用路由组件的API,比如history中的方法
需要手动引入该函数 在这里插入图片描述

该函数接收一个一般组件作为参数,它可以将该组件参数身上加上路由组件的方法。
使用方法,如果某个一般组件需要使用到路由组件身上的API(history,location,match),则在暴露该组件的时候。加上withRouter
在这里插入图片描述

5.2.7 BrowserRouter和HashRouter的区别

1.底层原理不一样
BrowserRouter使用的是h5中新加的history的API,不兼容IE9以下的版本
HashRouter使用的是URL的hash值
2.URL的表现形式不一样
BrowserRouter的路径中没有#,HashRouter的路径有#
3.刷新页面后对路由state参数的影响
BrowserRouter没有任何影响,因为state保存在history对象中
HashRouter刷新后会导致路由state参数的丢失
4.HashRouter可以用来解决一些路径错误相关的问题

6.React UI组件库 antd

6.1基本使用

npm安装antd
使用方法:比如你想使用里面的button按钮组件,首先需要import引入。此外,还需引入antd下的css文件

在这里插入图片描述
不同类型组件需要从不同地方引入(按需引入)比如想要用一个微信图标
在这里插入图片描述
详看文档

6.2 antd样式css文件的按需引入

由于在使用react脚手架创建的项目中的webpack配置文件是隐藏了的
如果想查看隐藏的配置,需要在终端输入命令 npm eject
官网中对按需引入的方法:
在这里插入图片描述
第一步安装库:
在这里插入图片描述
第一个是用来启动脚手架的,因为当你手动修改了原来的配置的时候,就不能用原来的npm start去启动脚手架了,必须借助该库。第二个库是用来修改配置的。
然后修改package.json里的配置,因为启动的命令发生了改变
在这里插入图片描述
下面的是修改后的
第二步在根目录下创建config-overrides.js
在这里插入图片描述
这里的原理就是暴露了一个函数,然后函数会接收到之前的配置(因为我们启动项目的命令改变了),然后函数体内改写配置并返回。
第三步需要引入一个按需加载的插件:babel-plugin-import。
在这里插入图片描述
修改config.overrides.js

在这里插入图片描述

最后在我们的代码中,就不用再自己引入样式了,删除引入antd.css的代码,它会帮我们按需引入。

6.3 antd自定义主题

比如当我们使用antd里的组件标签时,我们想自定义它的背景颜色。
antd官方自定义主题的方法:
在这里插入图片描述
修改后:
在这里插入图片描述
@primary-color变量就是antd在less中的主题颜色变量
新版less操作发生了改动:(以上是less7.0)
在这里插入图片描述
https://ant.design/docs/react/use-with-create-react-app-cn

7.redux简介

7.1 是什么

1.redux是一个专门用来做状态管理的JS库(不是React插件库)
2.作用:集中式管理react项目中的多个组件共享的状态。

7.2 什么情况下使用

1.某个组件的状态需要让其他组件可以随时拿到(共享)
2.一个组件需要和另一个组件通信
3.总体原则:能不用就不用,如果不用比较吃力就使用

7.3 原理图

在这里插入图片描述

7.3.1 reducer:

既可以加工状态也可以初始化状态,初始化状态时传入的previousState为undefined。加工时,根据旧的state和action,产生新的state的纯函数。

7.3.2 action

为动作对象,包含两个属性:type,标识属性,值为字符串,唯一,必要属性。data,数据属性,值类型任意,可选类型。

7.3.3 store

将state,action,reducer联系在一起的对象。
如何得到此对象:
1.import {createStore} from ‘redux’
2.import reducer from ‘./reducers’
3.const store =createStore(reducer)
此对象的功能:
getState():得到state
dispatch(action):分发action,触发reducer调用,产生新的state
subscribe(listener):注册监听,当产生新的state的时候,自动调用

7.3.4 基本使用

使用:npm i redux
创建相关文件目录
在这里插入图片描述
在store.js中,创建store对象
在这里插入图片描述
定义所需的reducer,并引入(函数形参=xx是赋默认值)
在这里插入图片描述
当你在页面上调用store.getState()方法的时候,store就会自动帮你调用reducer进行初始化拿到初始值。
在这里插入图片描述
会拿到0
其中,store会传递默认的previousState和action值(redux为了防止和程序员自身写的一些type重名所以type长这样,后面是随机值)
在这里插入图片描述
更改store中的值,使用store.dispatch
在这里插入图片描述
同时,在组件中使用componentDidMount钩子,注册一个监听(store.subscribe())当redux更新store中的值后,刷新页面,
我们在其回调函数中,调用this.setState({}),强制react调用render刷新页面
在这里插入图片描述
但是,这样做会有效率上的问题,所以可以在入口文件中(因为组件render会diff算法,所以不会有太大效率上的问题)在这里插入图片描述
在原理图中,我们可以看到还有一个createAction,它的作用主要就是创建action对象,所以,基于上面这个案例,可以创建出适用于该案例的createAction函数:

在这里插入图片描述
最终效果:
在这里插入图片描述
在真实开发中,我们还会定义action中类型的常量值,以防止incerment这种单词写错。
在这里插入图片描述

7.3.5同步action与异步action

同步action:对象形式的action
异步action:回调函数式的action
异步action需要使用一个中间件(redux-thunk),因为react规定action只能是对象。该中间件可以在store收到异步action的时候,直接执行该回调函数而不通过原来的reducer处理
需要安装引入该中间件,再从redux库中引入applyMiddleWare在store.js中用来配置中间件。作为第二个参数调用传入该函数在这里插入图片描述
总结:
首先在action中定义创建该异步action的函数
在这里插入图片描述
然后在store中引入并配置中间件
最后像平常那样使用:
在这里插入图片描述
在创建action时有一个优化,就是在回调函数中,会默认接收到一个dispatch参数,就不用使用store.dispatch
在这里插入图片描述
在实际开发场景中,我们通常是在这需要等一个异步的网络请求,拿到数据之后,再调用同步方法修改reducer的值。
在这里插入图片描述

8.react-redux(与redux不同,这是react官方出的插件库)

8.1模型图

在这里插入图片描述

8.2 基本使用

一般在实际开发中,components文件夹中一般放UI组件,在containers文件中存放容器组件。
定义一个容器组件时,需要借助于react-redux。

使用方法:
首先安装react-redux。
定义容器组件:
在这里插入图片描述
在App.js中,引入容器组件并挂载:并将store通过props的方式传给UI组件
在这里插入图片描述
在UI组件中,通过接收到的props中,使用redux的方法,以及父组件传过来的操作redux的数据的方法
在这里插入图片描述
总结:
在这里插入图片描述
容器组件中的简写形式:在mapDispatchToProps中,可以只用提供action,并且直接以对象的形式传入,react-redux会自动进行dispatch。(API层级的优化)
在这里插入图片描述

在这里插入图片描述
另外,在使用react-redux后,在项目的入口文件中,就不用再写store.subscribe监测redux中数据改变了。
补充:
在App.js中,如果有多个容器组件,那么就要传很多次的store,这样就代码需要优化
在这里插入图片描述
解决方法:我们可以在入库文件中,引入store,并在reaxt-redux引入一个Provider。该组件会自动分析项目中的所有容器组件,并传入store
在这里插入图片描述

8.3 整合容器组件和UI组件

在实际开发中一般如果一个组件需要UI组件和容器组件的话,我们会将其写在同一个jsx文件中。
在这里插入图片描述
优化总结:
在这里插入图片描述

8.4 多个组价共享状态

8.4.1 combineReducers

当有多个组价共享状态时,我们需要整合reducers,并且在redux中存储的数据应该是对象形式的。
在store中,我们需要引入combineReducers函数来整合多个reducer。该函数接收一个对象作为参数,该对象就是redux帮我们保存的总状态对象。.
在这里插入图片描述
在这时候,redux中保存的数据就是一个对象,分别有count和person,它们的值分别由countReducer和personReducer操作。
在这里插入图片描述

8.5 纯函数

8.5.1先补充一点:在reducer中,所暴露的函数必须是纯函数

在这里插入图片描述
比如在这里,当你使用数组方法对redux中person数组进行改变时,页面时是不会进行刷新的!!
原因:redux底层会进行一个浅比较,当它发现返回的preState与之前的preState的存储地址未发生改变时,它就不会进行页面的更新。

8.5.2 纯函数的概念:

1.一类特别的函数:只要是同样的输入(实参),必定得到同样的输出(返回),也就是说多次调用,参数相同,返回结果也应该相同
2.必须遵循以下原则:

不得改写参数数据(比如你传了一个参数为1,然后你将该参数改成了2)
不会产生任何副作用,例如网络请求,输入和输出设备
不能调用Date.now()或者Math,Random()等不纯的方法

8.6 react-redux开发者工具

1.极简插件中安装扩展工具。
2.在项目中安装redux-devtools-extension
3.在项目中的redux文件中的store.js文件中:
引入:
在这里插入图片描述
如果createStore没有写第二个参数,就可以直接写composWithDevTools
在这里插入图片描述
如果写了第二个参数,比如用于支持异步action的applyMiddleware(thunk)。就需要这样写
最后在项目开发中就可以使用该开发者工具了

9. 项目打包运行

npm run build
最终生成的build文件夹就是最终的打包文件。
运行serve -s build可以以build文件夹为根目录快速搭建一台服务器

10.扩展

10.1 setState

在这里插入图片描述

10.1.1 对象式的setState

调用时传入一个对象。

需要注意的是,setState是同步的方法,但是它后续引起的页面的更新是异步的。在setState中的第二个参数为一个回调函数,会在页面更新后调用执行。
假如你想要在更改完state后做出相应的操作,就可以在该回调函数中写

10.1.2 函数式的setState

调用时传入一个函数,该返回一个状态修改之后的state对象。该函数可以接收到state和props参数。

10.2 lazyLoad

路由组件的懒加载,借助于react中的lazy函数。
在这里插入图片描述
然后在引入组件时,就不要使用这种引入方法了
在这里插入图片描述
使用定义变量的形式引入,同时配合Suspense组件(需要从react中引入)
在这里插入图片描述
在注册路由的时候,使用Suspense组件包裹,传入一个fallback属性,值可以是虚拟DOM
在这里插入图片描述
表示当网速过慢,页面未加载出来时显示的内容。
fallback值也可以是组件(注意该组件不能用懒加载的方式写)

10.3 Hooks

10.3.1 是什么

React 16版本的新特性,可以使你在函数组件中使用state以及其他的react特性

10.3.2 常用的Hook

1.State Hook:React.useState()
2.Effect Hook:React.useEffect()
3.Ref Hook:React.useRef()

10.3.3 State Hook

在这里插入图片描述
useState()会返回一个数组,数组的第一个元素是state状态数据,第二个元素是更新状态的方法。
在这里插入图片描述
这个是数组的解构赋值

在这里插入图片描述
函数组件会调用1+n次,在你更改了state的数据后会调用,但是对于数组的解构赋值的那一行代码,React底层对其进行了处理,第一次调用的时候它就将count存了下来,不会因为第二次调用而覆盖掉之前的值。
更新状态的方法中,除了传递一个值,也可以传一个函数。接收原本的状态值,返回新的状态值,内部用其覆盖原来的状态值。
当有多个状态时,需要写多个useState函数
在这里插入图片描述

10.3.4 EffectHook

在函数组件中使用React.useEffect(),传入一个回调函数。当只传了一个回调函数的时候,它会在组件初始化,以及更新state时调用。因为没有传入第二个参数,就相当于监测所有人。
当你第二个参数传入一个空数组,则表示谁也不监测。数组中写state中的状态值,表示监测该状态值,当组件初始化,以及该状态值发生改变时,就会调用第一个参数,也就是回调函数
在这里插入图片描述
如果在函数组件中,需要用到类似于componentWillUnmount钩子,需要在React.useEffect()中返回一个函数,该返回的函数就相当于componentWillUnmount.。比如这里希望在组件将要卸载时清除定时器
在这里插入图片描述

总结:
在这里插入图片描述

10.3.5 Ref Hook

React.useRef()
使用方法:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
总结:
在这里插入图片描述

10.4 Fragment

作用:可以不用再写一个虚拟DOM的真实的根标签
在这里插入图片描述
在这里插入图片描述

10.5 context

在这里插入图片描述
作用:组件间通信方式,应用于跨代组件之间的通信。
需要注意的是,在创建context容器对象的时候,需要在全局创建。

10.6 pureComponent 组件优化

问题描述:当父组件中嵌套一个子组件,但是子组件自身并没有使用到任何父组件的数据。但是当父组件的state改变时,会调用自身的render,会导致子组件也重新刷新。且当调用setState时候,即使你传一个空对象,它也会调用render刷新
在这里插入图片描述
方法1:重写shouldComponentUpdate,该钩子默认接收到两个参数
在这里插入图片描述
重写该钩子,当要改变的状态和改变后的状态一致则返回false
在这里插入图片描述
在子组件中,当子组件未使用父组件的数据时或者父组件给子组件传递的数据是固定的变量,父组件的state改变引发的state不会牵连到子组件。
在这里插入图片描述
但是在开发中,我们一般不会自己重写。
最终方案:使用PureComponent代替Component

在这里插入图片描述
可以解决以上所有问题。

10.7 render Props

在这里插入图片描述
类似于vue中的slot
补充:组件标签的标签体内容是一个特殊的属性,叫children。子组件可以通过this.props.children拿到
在父组件中标签体的内容
在这里插入图片描述
那么这就产生了一个问题,A组件如何给自己的子组件B传递数据呢。
我们可以使用另一种构建父子组件的方法:
在这里插入图片描述
使用render方法,回调函数返回B组件
在A组件,调用render方法
在这里插入图片描述
然后,如果想传递参数的话,可以直接在render中写参数:
在这里插入图片描述

10.8 ErrorBoundary(错误边界)

10.8.1 简介

比如当某个子组件出问题时,我们不能因为这个错误而导致整个页面都出不来或者报错,或者影响其他组件也不能成功显示。只适用于生产环境,开发环境不能使用

10.8.2错误边界方法:

在容易出错的组件中的父组件里 加一个静态方法:getDerivedStateFromError(),它会在子组件报错时,调用getDerivedStateFromError里面的方法,并且在调用时会传入该错误。
该函数需要返回一个对象
在这里插入图片描述

10.8.3 componentDidCatch钩子

子组件渲染出错时,还会调用componentDidCatch钩子。通常我们在这个钩子统计错误次数,发送给后台
在这里插入图片描述

10.8.4 总结:

需要注意的是,只能监听子组件生命周期里的错误
在这里插入图片描述

11.组件通信方式总结

在这里插入图片描述

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值