React18.x-学习笔记


react核心库

  • react-development.js
  • react-dom-development.js
  • bebal.min.js

jsx语法规则

  • 定义虚拟Dom时,不要写引号。
  • 标签中混入js表达式要用{}。
  • 样式的类名指定不要用class 要用className
  • 内联样式,要用style={对象}—> style={{key:value}}的形式去写
  • 只能有一个根标签
  • 标签必须闭合或者单标签自闭合
  • 标签首字母
    1. 若小写字母开头,则将该标签转为html中同名元素,若HTML中无该标签对应的同名元素,则报错。
    2. 若大写字母开头,react就去渲染对应的组件,若组件没有定义,则报错。

灵魂拷问

  • 在复杂组件中 constructor构造函数执行几次?
    答:有几个复杂组件的实例就执行几次,只有一个组件实例则执行一次
  • 在复杂组件中render函数执行几次?
    答:当状态发生改变时则重新执行render函数 1+n次。 1代表初始化时执行。n代表状态(state)更新了几次。

组件三大特性

1.状态(state).
2.props.
3.ref

高阶函数

定义:什么是高阶函数?
如果一个函数符合下面2个规范中的任何一个,那该函数就是高阶函数。

  • 若A函数,接受的参数是一个函数,那么A就可以称之为高阶函数。
  • 若A函数,调用的返回值依然是一个函数,那么A就可以称之为高阶函数。
    常见的高阶函数有:Promise setTimeout arr.map() arr.reduce() arr.filter() arr.some() arr.sort() ….
    函数柯里化:通过函数调用继续返回函数的方式,实现多次接受参数最后统一处理的函数编码形式。

生命周期(重要)

在React17.0.0版本之前的生命周期钩子(旧版本)
执行顺序

  • constructor
  • componentDidMount 组件挂载前执行的钩子
  • render 函数在中间执行
  • componentDidMount 组件挂载完成后执行的钩子 //常用 比如:开启定时器,发送网络请求,订阅消息
  • componentWillUnmount 组件卸载前执行的钩子 //常用 比如:关闭定时器,取消订阅消息
    更新组件执行的生命周期钩子
  • shouldComponentUpdate 用于控制是否更新状态的钩子
    ​ 不写默认返回true 在组件中写入这个钩子必须要返回值
  • componentWillUpdate 组件更新前的钩子 即将废除
  • render 函数执行
  • componentDidUpdate 组件更新完毕执行钩子

新版本生命周期

  • 即将废除3个生命周期钩子 新增2个生命周期钩子
    即将废除:componentWillMount、componentWillReceiveProps 、componentWillUpdate
    这些钩子都是不常用的钩子
    新增钩子:getDerivedStateFromProps
    ​ getSnapshotBeforeUpdate

虚拟DOM的Diffing算法

  • 在循环列表项中加入Key值利于提高Diff算法的效率
  • diff算法比较新旧dom 然后根据key来判断旧的虚拟Dom节点是否可以复用。
  • 在循环列表项中如果要打乱顺序插入列表项,不要使用数组的索引值(index)来作为key使用。这样会发生严重后果且跟新效率低下。

订阅消息与发布消息 pubsub-js

安装订阅发布消息库 pubsub-js

  • yarn add pubsub-js
    在组件中引入pubsub库
    import PubSub from 'pubsub-js'
  • 在组件中发布消息。
    PubSub.publish(‘发布的消息名称’,payload(载荷/数据))
  • 在组件中订阅消息,一般在组件挂载完成的时候订阅,在componentDidMount钩子中订阅
    this.token = PubSub.subscribe(‘订阅的消息名称’,(mesName,data)=>{
    console.log(mesName,data)// 事件名称,收到发布消息的载荷
    })
    
  • 在组件卸载前取消订阅 componentWillUnmount钩子中取消订阅
    componentWillUnmount(){
     	PubSub.unsubscribe(this.token);
    }
    

react 路由

  • 核心库:react-router-dom

  • 路由组件的使用

    import {withRouter,HashRouter,BrowserRouter,Link,NavLink,Switch,Redirect,Route} from 'react-router-dom'
    
  • 各组件的功能

    • HashRouter组件,使用Hash模式的路由器,(用的不多)
    • BrowserRouter组件,浏览器使用的路由器,使用history模式进行路由切换,一般在SPA应用上包裹在App组件上。
    • Link组件,进行路由导航链接的组件
    • NavLink组件,进行路由导航链接的组件 多一个高亮效果,默认active类名。
      • 可以通过activename来更改选中时的类名
    • Switch组件,Switch包裹在路由组件中 <Switch> <Route/></Switch>中.
      • 用于对路由匹配的限制,匹配到了就不往下匹配了。就终止路由匹配
    • Redirect组件,重定向组件。一般用来兜底的组件。
      • 在路由组件什么也没匹配到的情况下,Redirect重定向到指定路径中。
    • Route组件 路由组件
      • 将一般组件变成路由组件,同时可以指定匹配的路径。路由组件中还会有this.props.history的API
    • withRouter 方法,
      • 将一般组件变成路由组件的函数,同时拥有historyAPI
      • 使用方式: withRouter(componentName)
      • 返回一个新组件,导出即可。
  • 路由的模糊匹配和嵌套路由。

    • 默认路由采用的是,模糊匹配。 如果想要严格匹配 加上 exact
    • 嵌套路由
      • 1.注册子路由时要写上父路由的path值
      • 2.路由的匹配是按照注册路由的顺序进行的
  • 路由传递参数(重要)

    		1.params参数
    					路由链接(携带参数):<Link to='/demo/test/tom/18'}>详情</Link>
    					注册路由(声明接收):<Route path="/demo/test/:name/:age" component={Test}/>
    					接收参数:this.props.match.params
    		2.search参数
    					路由链接(携带参数):<Link to='/demo/test?name=tom&age=18'}>详情</Link>
    					注册路由(无需声明,正常注册即可):<Route path="/demo/test" component={Test}/>
    					接收参数:this.props.location.search
    					备注:获取到的search是urlencoded编码字符串,需要借助querystring解析
    		3.state参数
    					路由链接(携带参数):<Link to={{pathname:'/demo/test',state:{name:'tom',age:18}}}>详情</Link>
    					注册路由(无需声明,正常注册即可):<Route path="/demo/test" component={Test}/>
    					接收参数:this.props.location.state
    					备注:刷新也可以保留住参数
    

redux要点

1. redux理解
2. redux相关API
3. redux核心概念(3个)
4. redux工作流程
5. 使用redux及相关库编码

1. redux理解

什么?: redux是专门做状态管理的独立第3方库, 不是react插件
作用?: 对应用中状态进行集中式的管理(写/读)
开发: 与react-redux, redux-thunk等插件配合使用

2. redux相关API

redux中包含: createStore(), applyMiddleware(), combineReducers()
store对象: getState(), dispatch(), subscribe()
react-redux: <Provider>, connect()()

3. redux核心概念(3个)

action: 
	默认是对象(同步action), {type: 'xxx', data: value}, 需要通过对应的actionCreator产生, 
	它的值也可以是函数(异步action), 需要引入redux-thunk才可以
reducer
	根据老的state和指定的action, 返回一个新的state
	不能修改老的state
store
	redux最核心的管理对象
	内部管理着: state和reducer
	提供方法: getState(), dispatch(action), subscribe(listener)

4. redux工作流程


5. 使用redux及相关库编码

需要引入的库: 
	redux
	react-redux
	redux-thunk
	redux-devtools-extension(这个只在开发时需要)
redux文件夹: 
	action-types.js
	actions.js
	reducers.js
	store.js
组件分2类: 
	ui组件(components): 不使用redux相关PAI
	容器组件(containers): 使用redux相关API

6.React-扩展

setState

setState更新状态的2种写法

	(1). setState(stateChange, [callback])------对象式的setState
            1.stateChange为状态改变对象(该对象可以体现出状态的更改)
            2.callback是可选的回调函数, 它在状态更新完毕、界面也更新后(render调用后)才被调用
					
	(2). setState(updater, [callback])------函数式的setState
            1.updater为返回stateChange对象的函数。
            2.updater可以接收到state和props。
            4.callback是可选的回调函数, 它在状态更新、界面也更新后(render调用后)才被调用。
总结:
		1.对象式的setState是函数式的setState的简写方式(语法糖)
		2.使用原则:
				(1).如果新状态不依赖于原状态 ===> 使用对象方式
				(2).如果新状态依赖于原状态 ===> 使用函数方式
				(3).如果需要在setState()执行后获取最新的状态数据, 要在第二个callback函数中读取

setState()的异步与同步

1). setState()更新状态是异步还是同步的?
    a. 执行setState()的位置?
        在react控制的回调函数中: 生命周期勾子 / react事件监听回调
        非react控制的异步回调函数中: 定时器回调 / 原生事件监听回调 / promise回调 /...
    b. 异步 OR 同步?
        react相关回调中: 异步
        其它异步回调中: 同步
2). 关于异步的setState()
    a. 多次调用, 如何处理?
        setState({}): 合并更新一次状态, 只调用一次render()更新界面 ---状态更新和界面更新都合并了
        setState(fn): 更新多次状态, 但只调用一次render()更新界面  ---状态更新没有合并, 但界面更新合并了
    b. 如何得到异步更新后的状态数据?
        在setState()的callback回调函数中

2. lazyLoad

路由组件的lazyLoad

	//1.通过React的lazy函数配合import()函数动态加载路由组件 ===> 路由组件代码会被分开打包
	const Login = lazy(()=>import('@/pages/Login'))
	
	//2.通过<Suspense>指定在加载得到路由打包文件前显示一个自定义loading界面
	<Suspense fallback={<h1>loading.....</h1>}>
        <Switch>
            <Route path="/xxx" component={Xxxx}/>
            <Redirect to="/login"/>
        </Switch>
    </Suspense>

3. Hooks

1. React Hook/Hooks是什么?

(1). Hook是React 16.8.0版本增加的新特性/新语法
(2). 可以让你在函数组件中使用 state 以及其他的 React 特性

2. 三个常用的Hook

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

3. State Hook

(1). State Hook让函数组件也可以有state状态, 并进行状态数据的读写操作
(2). 语法: const [xxx, setXxx] = React.useState(initValue)  
(3). useState()说明:
        参数: 第一次初始化指定的值在内部作缓存
        返回值: 包含2个元素的数组, 第1个为内部当前状态值, 第2个为更新状态值的函数
(4). setXxx()2种写法:
        setXxx(newValue): 参数为非函数值, 直接指定新的状态值, 内部用其覆盖原来的状态值
        setXxx(value => newValue): 参数为函数, 接收原本的状态值, 返回新的状态值, 内部用其覆盖原来的状态值

4. Effect Hook

(1). Effect Hook 可以让你在函数组件中执行副作用操作(用于模拟类组件中的生命周期钩子)
(2). React中的副作用操作:
        发ajax请求数据获取
        设置订阅 / 启动定时器
        手动更改真实DOM
(3). 语法和说明: 
        useEffect(() => { 
          // 在此可以执行任何带副作用操作
          return () => { // 在组件卸载前执行
            // 在此做一些收尾工作, 比如清除定时器/取消订阅等
          }
        }, [stateValue]) // 如果指定的是[], 回调函数只会在第一次render()后执行
    
(4). 可以把 useEffect Hook 看做如下三个函数的组合
        componentDidMount()
        componentDidUpdate()
    	componentWillUnmount() 

5. Ref Hook

(1). Ref Hook可以在函数组件中存储/查找组件内的标签或任意其它数据
(2). 语法: const refContainer = useRef()
(3). 作用:保存标签对象,功能与React.createRef()一样

4. Fragment使用

<Fragment><Fragment>
<></>

作用

可以不用必须有一个真实的DOM根标签了


## 5. Context ### 理解 > 一种组件间通信方式, 常用于【祖组件】与【后代组件】间通信 ### 使用 ```js 1) 创建Context容器对象: const XxxContext = React.createContext()
  1. 渲染子组时,外面包裹xxxContext.Provider, 通过value属性给后代组件传递数据:
    <xxxContext.Provider value={数据}>
    子组件
    </xxxContext.Provider>

  2. 后代组件读取数据:
    //第一种方式:仅适用于类组件
    static contextType = xxxContext // 声明接收context
    this.context // 读取context中的value数据

    //第二种方式: 函数组件与类组件都可以
    <xxxContext.Consumer>
    {
    value => ( // value就是context中的value数据
    要显示的内容
    )
    }
    </xxxContext.Consumer>

### 注意
	在应用开发中一般不用context, 一般都用它的封装react插件
<hr/>
## 6. 组件优化 Component与PureComponent
```js
1). Component存在的问题?
    a. 父组件重新render(), 当前组件也会重新执行render(), 即使没有任何变化
    b. 当前组件setState(), 重新执行render(), 即使state没有任何变化
2). 解决Component存在的问题
    a. 原因: 组件的shouldcomponentUpdate()默认返回true, 即使数据没有变化render()都会重新执行
    b. 办法1: 重写shouldComponentUpdate(), 判断如果数据有变化返回true, 否则返回false
    c. 办法2: 使用PureComponent代替Component
    d. 说明: 一般都使用PureComponent来优化组件性能
3). PureComponent的基本原理
    a. 重写实现shouldComponentUpdate()
    b. 对组件的新/旧state和props中的数据进行浅比较, 如果都没有变化, 返回false, 否则返回true
    c. 一旦componentShouldUpdate()返回false不再执行用于更新的render()
  
4). 面试题:
    组件的哪个生命周期勾子能实现组件优化?
    PureComponent的原理?
    区别Component与PureComponent?

## 7. render props ### 如何向组件内部动态传入带内容的结构(标签)? Vue中: 使用slot技术, 也就是通过组件标签体传入结构 React中: 使用children props: 通过组件标签体传入结构 使用render props: 通过组件标签属性传入结构,而且可以携带数据,一般用render函数属性 ### children props xxxx {this.props.children} 问题: 如果B组件需要A组件内的数据, ==> 做不到 ### render props }> A组件: {this.props.render(内部state数据)} C组件: 读取A组件传入的数据显示 {this.props.data}
# 8. 错误边界

理解:

错误边界(Error boundary):用来捕获后代组件错误,渲染出备用页面

特点:

只能捕获后代组件生命周期产生的错误,不能捕获自己组件产生的错误和其他组件在合成事件、定时器中产生的错误

使用方式:

getDerivedStateFromError配合componentDidCatch

// 生命周期函数,一旦后台组件报错,就会触发
static getDerivedStateFromError(error) {
    console.log(error);
    // 在render之前触发
    // 返回新的state
    return {
        hasError: true,
    };
}

componentDidCatch(error, info) {
    // 统计页面的错误。发送请求发送到后台去
    console.log(error, info);
}

9. 组件通信方式总结

组件间的关系:

  • 父子组件

  • 兄弟组件(非嵌套组件)

  • 祖孙组件(跨级组件)

几种通信方式:

1.props:

(1).children props

(2).render props

2.消息订阅-发布:

pubs-sub、event等等

3.集中式管理:

redux、dva等等

4.conText:

生产者-消费者模式

比较好的搭配方式:

父子组件:props

兄弟组件:消息订阅-发布、集中式管理

祖孙组件(跨级组件):消息订阅-发布、集中式管理、conText(开发用的少,封装插件用的多)


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM