一、JSX

1. JSX是什么?

jsx是一种JavaScript的语法扩展,也在很多地方称为JavaScript XML,类似XML语法,能够描述我们的UI界面,能与 JavaScript 融合在一起

2. JSX的使用

2.1 常规规范

  1. jsx结构中只能由一个根元素
  2. jsx结构通常会包裹一个(),将整个jsx当做一个整体,实现换行
  3. jsx可以使单标签,也可以是双标签,但是单标签必须以/>结尾

    2.2 注释的写法

    注释写法:{ / / }

2.3 jsx嵌入变量作为子元素

  • 当变量是Number、String、Array类型时,可以直接显示
  • 当变量是null、undefined、Boolean类型时,内容为空
    • 显示null、undefined、Boolean需要将其转换为字符串
    • 转换方式:toString、字符串拼接、String()
  • Object对象类型不能作为子元素,会报错

    2.4 jsx嵌入表达式

  • 运算表达式

  • 三元运算符
  • 执行一个函数

    2.5 jsx绑定属性

  • 基本绑定:title、href、src等

image.png

  • 绑定class属性:最好使用className

image.png

  • 绑定style属性:绑定对象类型

image.png

3. 事件绑定

3.1 this绑定方案

  • 方案一:通过bind显示绑定
  • 方案二:使用ES6 class fields 语法
  • 方案三:传入箭头函数,利用隐式绑定

    3.2 参数绑定

  • 情况一:获取event对象

  • 情况二:获取更多参数,传入一个箭头函数以及主动执行的事件函数,并传入其它相关的参数

image.png

4. 条件渲染

  • 根据条件给变量赋值不同的内容
  • 三元运算符
  • && 逻辑与运算

    • 当某一个值,有可能为 undefined 时,使用 && 进行条件判断

      5. 列表渲染

  • 使用 map 高阶函数

  • 过滤一些内容:使用 filter 函数
  • 截取数组中的一部分:slice 函数

image.png

5.1 列表中的Key

作用:提高diff算法的效率

6. JSX本质

实际上,jsx只是 React.createElement(component, props, …children) 函数的语法糖

参数一:type

  • 当前 ReactElement 的类型
    • 标签元素,如 div 则为“div”
    • 组件元素,直接使用组件元素的名称

参数二:config

  • jsx中的属性都在config中以对象的属性和值的形式存储

参数三:children

  • 存放在标签中的内容,以children数组的方式存储

image.png

二、React脚手架

1. 脚手架是什么?

传统的脚手架指的是建筑学的一种结构,在搭建楼房、建筑物时,临时搭建出来的一个框架
编程中的脚手架(Scaffold),是一种工具,帮助我们快速生成项目的工程化结构

  • 帮助我们快速搭建项目
  • 在模板的基础上进行项目开发或进行一些简单的配置修改
  • 可以保证项目的基本机构一致性,方便后期维护

脚手架让项目从搭建到开发,再到部署,整个流程变得快速和便捷

现流行的脚手架

  1. Vue:@vue/cli
  2. Angular:@angular./cli
  3. React:create-react-app

    2. 创建React项目

    image.png

    3. 项目目录结构分析

    image.png
    目录结构中有一个PWA相关的概念
  • PWA全称 progressive web app,即渐进式web应用
  • 一个PWA应用首先是一个网页,可以通过web技术编写一个网页应用(类似于手机上的app)
  • APP Manifest 和 Service Worker是用来实现PWA的安装和离线缓存的功能

PWA解决了哪些问题?

  1. 可以将网页应用添加至主屏幕
  2. 实现了离线缓存功能
  3. 实现了消息推送

三、React组件开发(一)

1. 什么是组件化开发?

将一个页面拆分成一个个的功能块,每个功能块完成属于自己的这部分独立的功能,那么之后整个页面的管理和维护就变得很容易了
组件开发核心思想:

  • 将一个页面分成很多个组件
  • 每个组件实现页面的一个功能块
  • 每个组件再进行细分
  • 组件本身再进行复用

2. React组件类型

  • 根据组件的定义方式
    • 函数组件(Function Component)
    • 类组件(Class Component)
  • 根据组件内部是否有状态需要维护
    • 无状态组件(Stateless Component)
    • 有状态组件(Stateful Component)
  • 根据组件的不同职责
    • 展示型组件(Presentational Component)
    • 容器型组件(Container Component)

函数组件、无状态组件、展示型组件主要关注UI的展示
类组件、有状态组件、容器型组件主要关注数据逻辑

2.1 类组件

定义要求

  • 组件名称大写字符开头
  • 必须继承 React.Component
  • 必须实现 render 函数

class定义一个组件

  • constructor是可选的,可以在其中初始化一些数据
  • this.state 维护的是组件内部的数据
  • render() 方法必须实现

render函数的返回值
当 render 被调用时,它会检测 this.props 和 this.state 的变化并返回以下类型之一

  • React元素:JSX元素(本质 React.createElement)
  • 数组或fragments:数组被遍历
  • Portals:可以渲染子节点到不同的 DOM 子树中
  • 字符串或数值类型:会在 DOM 中被渲染为文本节点
  • 布尔类型、null、undefined:都不会被显示

    2.2 函数式组件

    函数式组件是使用 function 来进行定义的函数,只是这个函数返回值与类组件中 render 函数返回的值一致 ```jsx //函数式组件 function App() { return

    app component

    }

export default App

  1. 函数式组件的特点
  2. 1. 没有生命周期函数
  3. 2. this关键字不能指向组件实例(因为没有组件实例)
  4. 3. 没有内部状态(state
  5. <a name="mjet7"></a>
  6. ## 3. 生命周期
  7. 生命周期:事物从创建到销毁的过程
  8. <a name="AyhuW"></a>
  9. ### 3.1 生命周期和生命周期函数
  10. - 生命周期:是一个抽象的概念,描述生命周期的整个过程
  11. - 挂载阶段(mount),组件第一次在DOM树中被渲染的过程
  12. - 更新阶段(update),组件状态发生变化,重新更新渲染的过程
  13. - 卸载过程(unmount),组件从DOM树中被移除的过程
  14. - 生命周期函数(常用):React告诉我们当前处于哪个阶段,会在组件内部实现某些函数进行回调
  15. - Constructor(可选)
  16. - 初始化数据(this.state
  17. - 为事件绑定实例(this
  18. - componentDidMount函数:组件已挂载到DOM上时回调
  19. - 依赖于 DOM 的操作可以在此执行
  20. - 在此发送网络请求
  21. - 在此添加一些订阅(在componentWillUnmount中取消订阅)
  22. - componentDidUpdate函数:组件发生了更新时回调(首次渲染不会执行)
  23. - 组件更新时,对 DOM 进行操作
  24. - 组件更新后,对 props 进行比较,然后进行相应的网络请求
  25. - componentWillUnmount函数:组件即将被移除时回调
  26. - 执行一些必要的清理操作
  27. - 清除一些 timer、取消网络请求、清除创建的订阅等
  28. ![image.png](https://cdn.nlark.com/yuque/0/2022/png/26749762/1666974362989-31e0d12b-dbcf-40bb-9c7c-d39fe4beac5b.png#averageHue=%23faf9f7&clientId=ua9121097-cd87-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=347&id=ub4404ff2&margin=%5Bobject%20Object%5D&name=image.png&originHeight=434&originWidth=1250&originalType=binary&ratio=1&rotation=0&showTitle=false&size=43370&status=done&style=none&taskId=u48d69b84-b97a-4e71-9382-79c16cb2d5d&title=&width=1000)
  29. - 生命周期函数(不常用)
  30. - getDerivedStateFromPropsstate 的值在任何时候都依赖于 props 时使用,该方法返回一个对象来更新state
  31. - getSnapshotBeforeUpdate:在 React 更新 DOM 之前回调的一个函数,可以获取 DOM 更新前的一些信息(比如滚动位置)
  32. - shouldComponentUpdateDOM 更新时控制 React 是否调用 render 函数,在做性能优化时会用到
  33. ![image.png](https://cdn.nlark.com/yuque/0/2022/png/26749762/1666974337593-b46299b8-5c75-42d3-b20f-4e3c1455b84c.png#averageHue=%23faf9f7&clientId=ua9121097-cd87-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=395&id=u3e39bdbb&margin=%5Bobject%20Object%5D&name=image.png&originHeight=667&originWidth=1293&originalType=binary&ratio=1&rotation=0&showTitle=false&size=57850&status=done&style=none&taskId=ubd3fc953-1471-4ec1-8a5d-4225dbf891f&title=&width=765)
  34. <a name="qwch3"></a>
  35. ## 4. 组件间的通信
  36. <a name="YCnv4"></a>
  37. ### 4.1 父传子
  38. - 父组件通过 **属性=值** 的形式传递给子组件
  39. - 子组件通过 **props** 参数获取父组件传递的数据
  40. :::tips
  41. 对于 props
  42. 1. 校验 propsComponent.propTypes = {}
  43. - 可使用 propTypes props 进行类型校验
  44. - 若使用FlowTypeScript,则可以直接进行类型验证
  45. 2. props默认值:Component.defaultProps = {}
  46. :::
  47. <a name="fv9CF"></a>
  48. ### 4.2 子传父
  49. 父组件传递给子组件一个回调函数,子组件通过 props 使用该回调函数,子组件利用回调函数给父组件传递参数
  50. <a name="F08GH"></a>
  51. ### 4.3 Context共享数据
  52. Context用于层层传递的数据
  53. - Context 提供了一种在组件之间共享此类值的方式,不必显式地通过组件树的逐层传递 props
  54. - Context 目的是为了共享那些对于一个组件树而言是“全局“的数据
  55. Context实现步骤(类组件)
  56. > 1. 创建一个Contextconst themeContext = React.createContext()
  57. > 2. 使用`<ThemeContext.Provider value={{name: 'coder'}}><Home/></ThemeContext.Provider>`包裹需要传递的子组件,并通过value属性设置需要共享的数据
  58. > 3. Home子组件(需要引入创建的Context)中显式地设置contentType值为themeContext`Home.contentType = themeContext`
  59. > 4. 在子孙组件中通过this.context获取共享的数据,并使用
  60. Context实现步骤(函数组件)
  61. > 1. 创建一个Contextconst themeContext = React.createContext()
  62. > 2. 在子孙组件中(需要引入创建的Context)使用ThemeContext .Consumer的方式获取共享数据并使用
  63. ![image.png](https://cdn.nlark.com/yuque/0/2022/png/26749762/1667058531933-ed126fe5-6e1b-4454-a7dd-9154a32d816b.png#averageHue=%23292c34&clientId=u93045b1a-9196-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=417&id=u663f064a&margin=%5Bobject%20Object%5D&name=image.png&originHeight=398&originWidth=777&originalType=binary&ratio=1&rotation=0&showTitle=false&size=130263&status=done&style=none&taskId=u2386e808-b486-4e4b-b990-e0d1fb6c5f1&title=&width=813.6000366210938)
  64. <a name="b9y3o"></a>
  65. ### 4.4 Event Bus
  66. 使用hy-event-storeevents第三方库
  67. <a name="ctqT1"></a>
  68. ## 5. React中的插槽
  69. React中其实没有插槽的概念,因为React很灵活,可以将自己需要的元素传入即可<br />使用两种方案实现插槽
  70. <a name="zJcA1"></a>
  71. ### 5.1 children实现
  72. 使用组件 children 子元素的方式:每个组件都可以获取到 props.children(包含组件开始标签和结束标签之间的内容)
  73. - 子元素为一个元素时,则 props.children = ReactElement
  74. - 子元素有多个元素时,则 props.children = [ReactElement1, ReactElement2, ReactElement3]
  75. - 缺点:通过索引值获取传入的元素很容易出错,不能精确获取传入的元素原生
  76. ![image.png](https://cdn.nlark.com/yuque/0/2022/png/26749762/1667052172001-1efbd266-90a8-441e-bcb0-7ca4b8e3dde2.png#averageHue=%23282d36&clientId=u93045b1a-9196-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=424&id=u8301432f&margin=%5Bobject%20Object%5D&name=image.png&originHeight=530&originWidth=970&originalType=binary&ratio=1&rotation=0&showTitle=false&size=135683&status=done&style=none&taskId=uff8a595d-0d20-419a-b9e3-7e722b17ff2&title=&width=776)
  77. <a name="HDotL"></a>
  78. ### 5.2 props实现(推荐)
  79. 使用 props 实现:通过具体的属性名,可以在传入和获取时更加精确
  80. - 模拟 Vue 作用域插槽,父组件传入一个回调函数,子组件调用回调并传入参数,在父组件那里可以获取子组件的参数并自定义元素类型
  81. ![image.png](https://cdn.nlark.com/yuque/0/2022/png/26749762/1667055629859-cf3c6598-e92a-4d88-9223-e0e176369bd0.png#averageHue=%23292d36&clientId=u93045b1a-9196-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=341&id=ue8bbe80a&margin=%5Bobject%20Object%5D&name=image.png&originHeight=502&originWidth=1136&originalType=binary&ratio=1&rotation=0&showTitle=false&size=122514&status=done&style=none&taskId=uf2c27b91-6700-4dff-8324-02bc5562afe&title=&width=772)
  82. <a name="sz3z8"></a>
  83. ## 6. 解析setState
  84. <a name="NHzW9"></a>
  85. ### 6.1 Vue和React渲染流程的对比
  86. <a name="MVzkk"></a>
  87. #### 6.1.1 Vue对数据管理和界面渲染的流程
  88. template进行词法分析、语法分析生成AST再生成JavaScriptAST最后生成render函数,相当于`<div></div> -> h("div", {}, "")`,并且在解析的过程中会对v-forv-model等指令进行处理,并进行数据劫持(Vue2使用Object.definePropertyVue3使用proxy)来监听数据的变化,当数据发生改变的时候会触发setter,执行相应的依赖,然后主动地调用render()进行数据更新
  89. <a name="Pjc9v"></a>
  90. #### 6.1.2 React对数据管理和界面渲染的流程
  91. React中没有像Vue那样对数据进行劫持,React中所有对数据的操作都是手动处理的,Reactrender函数是交给我们手动执行的,render函数返回的对象相当于`<div></div> -> React.createElement("div",{}, "")`,在类组件中我们通过this.state手动添加数据,通过this.setState手动去修改数据,然后React会自动调用render函数重新渲染,当修改的数据和原数据相同时,React也会调用render函数重新渲染,这样就会造成不必要的性能浪费,所以可以通过`shouldComponentUpdate()回调函数`去告知React当数据更新时需不需要调用render函数重新渲染;而PureComponent就是帮助我们去做这种优化的(当修改前和后相同时不执行render函数)
  92. <a name="CWDLk"></a>
  93. ### 6.2 setState三种用法
  94. 内部原理:this.setState会创建一个新的对象newState,内部通过Object.assign(this.state, newState)进行合并
  95. <a name="C3EOL"></a>
  96. #### 6.2.1 基本用法
  97. > this.setState({message: 'aaa'})
  98. <a name="EvmRG"></a>
  99. #### 6.2.2 可以传入一个回调函数
  100. ```jsx
  101. this.setState((state, props) => {
  102. // 优点:
  103. // 1.可以编写一些对新state处理逻辑
  104. // 2.可以获取之前的state和props值
  105. return {
  106. message: 'hello world'
  107. }
  108. })

优点:

  1. 可以编写一些对新state处理逻辑
  2. 可以获取之前的state和props值

    6.2.3 setState是一个异步调用

    setState执行之后不会立马合并数据,如果希望调用setState后能够立马获取到更新之后的数据,可以利用setState的第二个参数:传入一个callback,在callback中可以获取到最新的数据
    1. this.setState({message: 'aaa'}, () => {
    2. console.log(this.state.message) // 最新的数据:message: 'aaa'
    3. })
    ⭐为什么setState设计为异步?
  • setState设计为异步能显著的提升性能
    • 如果每次调用 setState 都进行一次更新,那么意味着 render 函数会被频繁触发调用,界面重新渲染,效率很低
    • 设计为异步能够获取到多个更新,并批量处理更新
      • 将多个更新操作放入一个队列当中,当执行render时,将队列中的state拿出来依次合并,进行一次render即可
  • setState设计为异步能保持state和props同步

    • 如果同步更新了 state, 但还没执行 render 函数,那么 state 和 props 不能保持同步

      6.3 setState一定是异步的嘛?

      6.3.1 在 React18 之前

  • 只有在 React 事件中才会进行批处理(异步)

  • 在Promise回调、setTimeout回调、原生DOM事件回调中 setState 是同步的

    6.3.2 在 React18之后

    默认所有的操作都进行批处理(异步处理),能够获得更高的性能
    image.png
    如果要使得 setState 同步处理,那么就需要使用 react-dom 包中的 flushSync函数

    1. import { flushSync } from 'react-dom'
    2. setTimeout(() => {
    3. flushSync(() => {
    4. // 该回调下的所有setState会进行批处理
    5. this.setState({ message: ''})
    6. })
    7. console.log(this.state.message) // 这里会同步地拿到最新的数据
    8. }, 0)

    四、React组件开发(二)

    1. React更新机制

    image.png
    React 在 props 或者 state 发生改变的时候,会调用 React 的 render 方法,创建一颗不同的树,React基于这两棵不同的树之间的差异来判断如何有效的更新UI(diff算法)
    React的diff算法:

  • 同层及诶单之间相互比较,不会跨节点比较

  • 不同类型的结点,产生不同的树结构
  • 可以使用key来复用节点,使得diff算法效率更高

    2. render函数的优化

    2.1 shouldComponentUpdate(nextPops, nextState)

  • 对前后props/state做一个浅层比较(引用不同就返回true)

  • 函数参数
    • nextProps:更新后的props属性
    • nextState:更新后的state属性
  • 返回值:返回一个Boolean类型
    • true:需要调用render函数(默认)
    • false:不需要调用render函数

      当state或props的数据发生变化时,shouldComponentUpdate函数能够控制render函数是否重新执行,当state或props的值发生改变的时候,再执行render函数,否则不执行不重新渲染,那么就可以提高性能

  1. shouldComponentUpdate(nextPops, nextState) {
  2. if(this.state.message !== nextState.message) {
  3. return true // 会执行render函数
  4. }
  5. return false // 不会执行render函数
  6. }

2.2 PureComponent(类组件)

PureComponent是React帮助我们实现好的一个类,它内部做的事情就是我们使用shouldComponentUpdate时做的事情,根据props或state中的数据是否发生改变,来决定是否重新执行render函数

  1. // 使用类组件时,可以继承PureComponent,进行性能优化
  2. import { PureComponent } from 'react'
  3. class App extends PureComponent {
  4. ...
  5. }

2.3 memo(函数式组件)

在函数式组件中,使用React提供的memo函数对组件进行包裹,也可以帮助我们判断是否重新执行render函数

  1. import { memo } from 'react'
  2. const Home = memo(function(props) {
  3. return <h1>{props.message}</h1>
  4. })
  5. export default Home

2.4 不可变的力量

在开发过程中,不要直接修改state当中的值(对象类型),可以先进行一个拷贝再通过setState进行修改,如果直接修改state中的值,比如 this.state.books.push(newBook); this.setState({ books: this.state.books}) ,这时如果组件继承至PureComponent,那么组件将不会执行render函数进行相应的更新;因为直接修改this.state.books时,此时PureComponent会认为前后的state是相同的(对象引用相同)那么就不会执行render函数

3. ref

3.1 ref的作用

ref可以用来获取DOM元素或组件实例(类组件),进行某些操作

  • 管理焦点,文本选择或媒体播放
  • 触发强制动画
  • 集成第三方DOM库

    3.2 ref的使用

    3.2.1 类组件使用ref的三种方式

  • 在React元素上绑定一个ref字符串,元素对象会被放到this.refs.xxx中(不推荐)

image.png

  • 使用 react 库中的 createRef() 创建一个ref对象,在React元素中使用ref绑定该对象,那么元素对象就会被放到ref对象的current属性当中(该方法也能绑定组件实例)

image.png

  • 给ref属性传入一个回调函数,在对应元素被渲染之后,回调函数会执行并传入该元素对象

image.png

3.2.2 函数组件使用ref的方式(ref转发)

ref不能应用与函数式组件,因为函数式组件没有实例,不能获取到对应的组件实例,但可以通过ref转发的方式获取到函数式组件中的元素

使用forwardRef高阶函数

image.png

4. 受控和非受控组件

4.1 受控组件

官方定义:
image.png
简单来说:受控组件就是那些通过代码控制的表单元素
image.png

4.2 非受控组件

非受控组件就是表单数据交由 DOM 节点来处理

  • 使用 ref 获取非受控组件中的表单数据(因为不能绑定 value ,否则会变成受控组件)
  • 使用 defaultValue 属性来设置非受控组件的默认值

5. 高阶组件

5.1高阶组件的定义

高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧。HOC 自身不是 React API 的一部分,它是基于 React 的组合特性而形成的设计模式
具体而言:高阶组件是参数为组件,返回值为新组件的函数
高阶组件在一些 React 第三方库中很常见:

  • 如 redux 中的 connect
  • 如 react-router 中的 withRouter

    5.2 高阶组件的应用

    5.2.1 props增强

  • 不修改原有代码情况下,添加新的 props

  • 利用高阶组件来共享 Context,复用组件逻辑

image.png

5.2.2 登录鉴权

image.png
高阶组件能够对传入的组件进行拦截,根据情况进行相应的渲染

5.2.3 生命周期劫持

计算渲染时间
image.png
可以利用高阶组件来劫持生命周期,在生命周期中完成自己的逻辑

5.3 高阶函数的意义

优点:利用高阶组件可以针对某些 React 代码进行更加优雅的处理
缺点:

  • HOC 需要在原组件上进行包裹或嵌套,若大量使用 HOC,会产生大量嵌套,让调试变得非常困难
  • HOC 可以劫持 props,在不遵守约定的情况下会造成冲突

    6. Portals

    Portal 提供了一种将子节点渲染到存在于父组件以外的 DOM 节点的优秀方案,类似于Vue3的teleport

  • 第一个参数(child)是任何可渲染的 React 子元素,例如一个元素、字符串或 fragment

  • 第二个参数(container)是一个 DOM 元素,即需要挂载的元素

典型用例:对话框、悬浮卡、提示框等

7. fragment

fragment 允许将子列表分组,无需向 DOM 添加额外节点。比如每次返回元素时都要写一个 div 元素表示根节点,可以使用 fragment 将其分组就无需写 div 元素,fragment 也不会被渲染。

fragment 短语法

  • <></>
  • 当需要在 fragment 中添加 key 时,就不能使用短语法

8. StrictMode

8.1 StrictMode的定义

StrictMode 是一个用来突出显示应用程序中潜在问题的工具(严格模式)

  • 与 fragment 一样,StrictMode 不会渲染任何可见UI
  • 它为其后代元素触发额外的检查和警告
  • 严格模式检查仅在开发模式下运行,不会影响生产构建

    8.2 StrictMode的作用

    开启严格模式后的检测
  1. 识别不安全的生命周期
  2. 识别过时的ref API
  3. 检测额外的副作用。组件的 constructor 会被调用两次,这是严格模式下故意进行的操作,为了查看调用多次时是否会产生其它副作用,在生产环境中不会调用两次
  4. 检测废弃的 findDOMNode 方法
  5. 检测过时的 context API

    五、React Transition Group(React动画)

react-transition-group 是由社区维护的一个提供css动画的第三方库,这个库可以很方便地实现组件的入场和离场动画,使用时安装即可

# npm
npm install react-transition-group —save
# yarn
yarn add react-transition-group

react-transition-group 主要包含四个组件:

  • Transition
    • 该组件是一个和平台无关的组件(不一定要结合CSS)
    • 前端开发中,主要结合CSS来完成样式,所以比较常用的是CSSTransition
  • CSSTransition
    • 使用 CSSTransition 来完成过渡动画
  • SwitchTransition
    • 两个组件显示和隐藏切换时,使用该组件
  • TransitionGroup

    • 将多个动画组件包裹其中,一般用于列表中元素的动画

      1. CSSTransition

      1.1 CSSTransition介绍

      CSSTransition 是基于 Transition 组件构建的,CSSTransition 执行过程中,有三个状态:appear、enter、exit,并且每个状态需要定义对应的 CSS 样式
  • 开始状态:对于的类是 -appear、-enter、-exit

  • 执行动画:对应的类是 -appear-active、-enter-active、-exit-active
  • 执行结束:对应的类是 -appear-done、-enter-done、-exit-done ```css .show-appear, .show-enter { opacity: 0; }

.show-appear-active, .show-enter-active { opacity: 1; transition: opacity 2s ease; }

.show-exit { opacity: 1; }

.show-exit-active { opacity: 0; transition: opacity 2s ease; }

  1. ![image.png](https://cdn.nlark.com/yuque/0/2022/png/26749762/1667492399055-d89a908e-f7a0-4a06-a7f9-f0b1e816de8b.png#averageHue=%23282d35&clientId=uad0657e4-395b-4&crop=0&crop=0&crop=1&crop=1&from=paste&id=u1d6d58f9&margin=%5Bobject%20Object%5D&name=image.png&originHeight=294&originWidth=875&originalType=binary&ratio=1&rotation=0&showTitle=false&size=34692&status=done&style=none&taskId=u7092bd86-1bef-4117-9a42-e7e858ff51d&title=)
  2. <a name="XrZ1l"></a>
  3. ### 1.2 CSSTransition常见属性
  4. CSSTransition常见属性:
  5. - in:触发进入或者退出状态(boolean
  6. - 如果添加了 unmountOnExit={true},那么该组件会在执行退出动画结束后被移除掉
  7. - in true 时,触发进入状态,会添加 -enter、-enter-active类开始执行动画,当动画执行结束后,会移除两个class,并且添加 -enter-done
  8. - in false 时,触发退出状态,会添加 -exit、-exit-active类开始执行动画,当动画执行结束后,会移除两个class,并且添加 -exit-done
  9. - classNames:决定了动画 class 的名称
  10. - timeout:决定类添加或移除的时间(一般与动画时间一致)
  11. - appear:是否在初次进入时添加动画(需要和 in 同时为 true
  12. - unmountOnExit:退出动画后是否卸载组件
  13. <a name="sXYHf"></a>
  14. ### 1.3 CSSTransition钩子函数
  15. CSSTransition 对应的钩子函数:主要为了检测动画的执行过程并完成一些 JavaScript 操作
  16. - enter
  17. - onEnter:在开始**进入**动画之前触发
  18. - onEntering:在执行**进入**动画时触发
  19. - onEntered:在执行**进入**动画结束后触发
  20. - exit
  21. - onExit:在开始**离开**动画之前触发
  22. - onExiting:在执行**离开**动画时触发
  23. - onExited:在执行**离开**动画结束后触发
  24. <a name="Fy5jG"></a>
  25. ## 2. SwitchTransition
  26. SwitchTransition可以完成两个组件间切换的动画
  27. <a name="d32Ep"></a>
  28. ### 2.1 SwithTransition常见属性
  29. SwithTransition常见属性:
  30. - mode
  31. - in-out:表示新组件先进入,旧组件再移除
  32. - out-in:表示旧组件先移除,新组件再进入(默认)
  33. <a name="BvIVI"></a>
  34. ### 2.2 SwithTransition的使用
  35. - SwithTransition 组件内要用 CSSTransition 或者 Transition 组件对需要切换的组件进行包裹
  36. - SwithTransition 里面的 CSSTransition Transition 不再像以前那样接受 in 属性来判断元素是何种状态,取而代之的是 key 属性
  37. ```css
  38. .login-enter {
  39. transform: translateX(-100px);
  40. opacity: 0;
  41. }
  42. .login-enter-active {
  43. transform: translateX(0);
  44. opacity: 1;
  45. transition: all 1s ease;
  46. }
  47. .login-exit {
  48. transform: translateX(0);
  49. opacity: 1;
  50. }
  51. .login-exit-active {
  52. transform: translate(100px);
  53. opacity: 0;
  54. transition: all 1s ease;
  55. }

image.png

3. TransitionGroup

当我们有一组动画时,需要将这些 CSSTransition 放入到 TransitionGruop 中来完成动画
image.png

六、React中的CSS

1. 组件化开发中的CSS

组件化中 CSS 需要符合的条件:

  • 可以编写局部CSS:CSS具备自己的作用域,不会随意污染其它组件内的元素
  • 可以编写动态的CSS:可以获取当前组件的一些状态,根据状态变化生成不同的CSS样式
  • 支持所有的CSS特性:伪类、动画、媒体查询等
  • 编写起来简单方便、最好符合一贯的CSS风格特点

    1.1 Vue中编写CSS

    Vue中CSS编写的特点:

  • Vue 通过在 .vue 文件文件中使用 标签来编写自己的样式

  • 通过 scoped 属性来决定样式是全局还是局部
  • 通过 lang 属性来设置预处理器less、sass
  • 通过内联样式的风格方式来根据最新状态设置和改变CSS

    2. React中CSS编写方式

    2.1 内联样式

    内联样式是官方推荐的一种CSS样式写法:

  • style接受一个采用小驼峰命名属性的 JavaScript 对象,而不是CSS字符串

  • 并且可以引用 state 中的状态来设置相关样式

内联样式的优点:

  • 样式之间不会产生冲突
  • 可以动态获取state中的状态

内联样式的缺点:

  • 代码提示差,写法上都需要使用驼峰标识
  • 大量的内联样式会造成代码混乱
  • 某些样式无法编写(如伪类/伪元素)

image.png

2.2 普通的CSS

这种编写方式就是写一个单独的样式文件,通过import引入,但这种方式都属于全局的CSS,样式之间会相互影响

2.3 CSS Modules

2.3.1 CSS Modules的介绍

  • CSS Modules并不是 React 特有的解决方案,而是所有使用了类似于 webpack 配置的环境下都可以使用(配置webpack.config.js中modules: true)
  • React脚手架已经内置了CSS Modules的配置
    • .css/.less/.scss等样式文件都需要修改成 .module.css/.module.less/.module.scss等
    • 使用import引入,并通过模块的方式使用
  • CSS Modules解决了局部作用域的问题

底层原理
image.png

2.3.2 CSS Modules的缺点

  • 引用的类名不能使用连接符,在JavaScript中是不识别的
  • 所有的className都必须使用 {style.className} 的形式来编写
  • 不方便动态修改样式,依然需要使用内联样式的方式

    2.3.3 CSS Modules的使用

    ```css .title { font-size: 32px; color: ‘blue’; }

``` image.png

2.4 CSS in JS(styled-components)

CSS in JS 是指一种模式,其中CSS由JavaScript生成而不是在外部文件中定义,它是由第三方库提供;简单来说,CSS in JS就是将CSS也写入到JavaScript中的方式,并且可以方便的使用JavaScript的状态

  • CSS in JS 通过JavaScript来为CSS赋予一些能力,包括类似于CSS预处理器一样的样式嵌套、函数定义、逻辑复用、动态修改状态等
  • 比较流行的 CSS in JS 库
    • styled-components
    • emotion
    • glamorous

      2.4.1 安装

      npm install styled-components

      2.4.2 使用

  1. 使用styled创建样式组件,可使包裹的元素应用样式
  2. 可接收外部传入的props
  3. 可以通过attrs设置默认样式
  4. 可以从外部引入变量

image.png

  1. 设置样式主题,共享样式属性

image.png

  1. 支持样式的继承

image.png

3. 动态添加class

最简单的就是通过判断来动态添加class,但这样做会导致代码可读性差,代码冗余等问题
image.png
我们可以借助第三方库:classnames
image.png

七、Redux

1. Redux的核心思想

1.1 理解JavaScript纯函数

在程序设计中,若函数符合以下条件,则为纯函数

  • 确定的输入,一定会产生确定的输出
  • 函数在执行过程中,不能产生副作用

    副作用:表示在执行一个函数时,除了返回函数值之外,还对调用函数产生了附加的影响,比如修改了全局变量,修改外部参数或者修改外部的存储

在React当中无论是声明函数式组件还是类组件,都要像纯函数一样保护它们的props不被修改

1.2 为什么需要Redux

  • JavaScript开发的应用程序越来越复杂,这些状态包括服务器返回的数据、缓存数据、用户操作产生的数据等;也包括一些UI状态,比如某些元素是否被选中、是否加载动画效果、保存当前分页等
  • 管理不断变化的state是非常困难的,状态之间会相互依赖,一个状态的变化会引起另一个状态的变化,也会影响view页面的变化,当应用程序复杂时,state 在什么时候,因为什么原因发生了变化,发生了什么变化,会变得非常难以控制和追踪
  • React只是在视图层帮我们解决了DOM的渲染过程,但state依然需要我们自己来管理

Redux就是一个帮助我们管理state的容器:Redux是 JavaScript 的状态容器,提供了可预测的状态管理

Redux除了和React一起使用之外,还可以与其它界面库一起使用,比如:Vue

1.3 Redux的核心理念

1.3.1 store

store就是用来存储数据的地方

1.3.2 action

Redux要求我们通过action来更新数据:

  • 所有数据的变化,必须通过派发(dispatch)action来更新(为了使数据可预测、可追踪)
  • action 是一个普通的 JavaScript 对象,用来描述这次更新的 type 和 content

    1.3.3 reducer

    reducer是一个纯函数,它做的事情就是将传入的state和action结合起来生成一个新的state

两个参数:

  • 参数一:store中目前保存的state
  • 参数二:本次需要更新的action(dispatch传入的action)

返回值:它的返回值会作为store之后存储的state

1.4 Redux的三大原则

1.4.1 单一数据源

  • 整个应用程序的state被存储在一颗object tree中,并且整个object tree只存储在一个 store 中
  • Redux并没有强制让我们不能创建多个store,但是那样并不利于数据的维护
  • 单一的数据源可以让整个应用程序的state变得方便维护、追踪、修改

    1.4.2 State是只读的

  • 唯一修改state的方法一定是触发action,不要试图在其他地方通过任何的方式来修改state

  • 这样就确保了view或网络请求都不能直接修改state,它们只能通过action来描述如何修改state
  • 这样可以保证所有的修改都被集中化处理,并安装严格的顺序来执行,无需担心race condition(竞态)问题

    1.4.3 使用纯函数来执行修改

  • 通过reducer将旧state和actions联系在一起,并且返回一个新的state

  • 随着应用程序的复杂度增加,可以将reducer拆分成多个小的reducers,分别操作不同state tree的一部分
  • 所有的reducer都应该是纯函数,不能产生任何副作用

    2. Redux的使用详解

    2.1 基本使用

  1. 创建一个对象作为初始状态(initialState)

image.png

  1. 创建store,并创建reducer函数

image.png

  1. 通过action来修改state
    • 通过dispatch来派发action
    • 被派发的对象会被传到reducer函数的第二个参数中

image.png

  1. 在reducer中处理代码,reducer是纯函数,不能直接修改state

image.png

  1. 可以在派发action之前,通过 store.subscribe(callback) 函数监听store的变化

    2.2 Redux结构划分

    image.png
  • stroe/index.js:创建store,导出store
  • store/actionCreators.js:存放各种action
  • store/constants.js:将 action 的 type 进行抽取,使用常量的方式保证代码的一致性
  • store/reducer.js:定义初始化数据,编写reducer函数逻辑

    2.3 Redux使用过程

    React中Redux使用过程
    image.png
  1. 创建store、reducer,并初始化state
  2. 组件在componentDidMount中订阅store
  3. 组件可以主动派发action去更新state,在reducer中执行相应的逻辑,返回新的state,并触发订阅
  4. 当state发生变化的时候,调用setState更新数据(调用render函数重新渲染)

    3. react-redux

    3.1 react-redux的基本使用

  5. 使用Provider包裹 App 组件(Provider和context类似能将store中state的数据共享给包裹的组件,因为所有组件可能都需要使用,那么就包裹App组件)

image.png

  1. 在组件中通过connect函数来进行store映射;connect函数是一个高阶组件,它内部的操作和我们手动使用redux一样,connect将这些逻辑抽取出来写成高阶组件,可以根据映射关系,将所需的state数据和dispatch映射到组件中

image.png

  1. 在prop中获取所需的state和派发action的函数进行使用

image.png