React学习笔记

React 高级内容

React 的数据视图更新原理

  1. state 数据
  2. JSX 模版
  3. 数据 + 模版 生成虚拟 DOM(虚拟 DOM 就是一个 JS 对象,用它来描述真实 DOM )(损耗了性能)
  4. 用虚拟 DOM 的结构生成真实的 DOM 来显示
  5. state 发生变化
  6. 数据 + 模版 生成新的虚拟 DOM(极大地提升了性能)
  7. 比较原始虚拟 DOM 和新的虚拟 DOM 的区别(极大地提升了性能)
  8. 直接操作 DOM,改变上一步中被修改了的的内容

优点:

  1. 性能提升
  2. 它使得跨端应用得以实现,React Native。

虚拟 DOM 中的 Diff 算法

问:什么时候会需要比对?
答:数据发生变化的时候,其实就是调用 setState 方法的时候

  1. setState 方法是异步的,可以把多次 setState 统一到一起,减少 DOM 比对的次数
  2. 虚拟 DOM 是同级比对的,如果比对有差异,下面级别的就不用比对了,直接把替换下面所有的级别

虚拟DOM比对

  1. 虚拟 DOM 循环的时候,要给定一个唯一的 Key(最好是唯一标识 ID 之类的,不能重复的),不要使用索引作为 Key

Ref 的使用

  1. ref 可以帮助我们获取 DOM 元素
  2. setState 是异步函数,它接收的第二个参数是 setState 完成后的回调函数 setState(() => ({}), () => {})

React 的生命周期函数

生命周期函数指在某一时刻组件会自动调用执行的函数,前面讲到的 render 函数就是一个生命周期函数。

Mounting

  • componentwillMount 函数在组件即将被挂载到页面的时刻执行,只有第一次挂载才会执行
  • render 可以认为就是所谓的组件挂载函数
  • componentDidMount 函数在组件挂载到页面之后,自动被执行,只有第一次挂载才会执行

Updation

  • 组件被更新之前,shouldComponentUpdate(nextProps, nextState) 函数就会被自动执行。shouldComponentUpdate(nextProps, nextState) 函数返回 true 或 false。
    如果返回值为 false,组件和数据就不会更新,它之后的生命周期函数都不会被执行
  • 组件被更新之前,shouldComponentUpdate 函数之后,componentWillUpdate 函数会被自动执行
  • 组件更新完成之后,componentDidUpdate 函数会被自动执行
  • 一个组件从父组件接受参数,只要父组件的render函数被重新执行了,子组件的 componentWillReceiveProps 就会被执行,或者用下面的两条描述
    • 如果子组件第一次存在于父组件中,子组件的 componentWillReceiveProps 函数不会执行
    • 如果子组件之前存在于父组件中,子组件的 componentWillReceiveProps 函数才会执行

Unmounting

  • 当这个组件即将被从页面中剔除的时候,componentWillUnmount 函数会被自动执行

每一个组件都有这样的生命周期函数,不是只有父组件才有。

React 生命周期函数的使用场景

Component 默认内置了其他所有的生命周期函数,但唯独没有内置render这个生命周期函数

  1. 借助 shouldComponentUpdate 可以避免无谓组件render函数的运行,提高性能
1
2
3
4
// nextProps是新的属性值
shouldComponentUpdate(nextProps, nextState) {
return nextProps.content !== this.propscontent
}
  1. ajax 请求,因为只请求一次,所以不放在render()函数里面执行,建议放在componentDidMount执行;放在 componentwillMount 可能会和 rn 开发有冲突。

性能优化:

  • 周期函数:shouldComponentUpdate(nextProps, nextState),提高组件性能
  • 作用域的修改:放在constructor里面。比如:this.handleClick.bind(this),只会执行一次,避免子组件无谓渲染
  • react 的底层setState,内置性能提升机制,异步函数,把多次数据改变结合一一次来做,降低虚拟 DOM 比对频率
  • react 底层用的是虚拟DOM的概念,同层比对,还有 key 值这样的概念,提升虚拟 DOM 比对速度

使用 Charles 实现本地数据 mock

Charles 可以抓取到浏览器的请求,然后返回指定数据文件的结果。

React 中实现 CSS 过渡动画

1
2
3
4
5
handleToggle() {
this.setState({
show: !this.state.show //可以这样写
})
}

animation 的最后一个参数填写 forwards,它能够在动画结束之后保存最后一帧 css 的样式

使用 react-transition-group 实现动画

安装 react 动画库

1
npm install react-transition-group --save

第一次展示到页面上的时候也要动画效果,用 appear={true}

Redux 入门

react只是一个轻量级的视图层框架,如果要做大型应用就要搭配视图层框架redux一起使用

redux = reducer + flux,flux升级成了redux

redux组件之间的传值非常简单,redux里面要求我们把数据都放在一个公共的存储区域store里面,组件之中尽量少放数据,也就是
所有数据都不放在组件自身了,都把它放到一个公用的存储空间里面,然后组件改变数据就不需要传递了,改变store里面的数据之后
其它的组件会感知到里面的数据发生改变。这样的话不管组件的层次有多深,但是走的流程都是一样的,会把数据的传递简化很多。

redux传值

Redux 的工作流程

redux是视图层框架,把所有数据都放在store之中,每个组件都要从store里拿数据,然后每个组件也要去改store里面的数据,

redux 的工作流程

举例:把这个流程理解成一个图书馆的流程
react compontents: 借书的人
action creators: “要借什么书”这句话(语句的表达,数据的传递)
store: 图书馆管理员(没办法记住所有书籍的存储情况)
reducers: 图书馆管理员的记录本(要借什么书,先查有没有,要还的书查一下放到某个位置);
借书的人~我要借一本书~图书管理员听见~查阅reducers手册~去store找书~把对应的书给借书人;

创建 Redux 的 Store

  1. npm安装Redux
  2. 在store文件夹下创建index.js,import { createStore } from ‘redux’
  3. 在store文件夹下创建reducer.js

    1
    2
    3
    4
    5
    6
    const defaultState = {
    inputValue:'123'
    }
    export default (state = defaultState,action) => {
    return state;
    }
  4. index.js中const store = createStore(reducer);

  5. 在组件中引入,this.state = store.getState()

Action 和 Reducer 的编写

  1. react首先要改变stroe里的数据,先要派发一个action, action通过dispatch(action)方法传给store
  2. stroe 把之前的数据和action(previousState,action)传给reducer
  3. reducer是个函数,它接收了state和action以后做些处理会返回一个新的newState给到store
  4. stroe用这个新的state替换到原来的数据,stroe数据改变了以后,react组件感受到了数据变化,它会从store里面重新取数据,更新组件的内容,页面就会跟着发生变化了

Reducer 可以接收 state,但是不能修改 state。

如果常量或变量在代码里写错的时候,是会报出异常的,就可以迅速定位到问题,但是如果写一个字符串的话就不会报出异常,那样的话
出了bug非常难调,所以才要进行ActionTypes的拆分。

store文件夹下创建一个actionCreators.js,把action都集中写在一个文件中,方便后期维护和自动化测试

Redux 知识点复习补充

  • redux三个基本原则:
    • store必须是惟一的。
    • 只有store能够改变自己的内容。
    • Reducer必须是纯函数。
  • 纯函数:给定固定输入,就一定会有固定的输出,而且不会有任何副作用。
  • redux 核心 api:
    • createStore:创建store;
    • store.dispatch:派发action,action会传递给store。
    • store.getState:获取到store里面所有的数据。
    • store.subscribe:订阅store的改变,store改变会触发store.subscribe接受的回调函数执行。

Redux 进阶

UI组件和容器组件

  • UI 组件负责页面的渲染(傻瓜组件)
  • 容器组件负责页面的逻辑(聪明组件)

无状态组件

当一个组件只有 render 函数时,可以用无状态组件代替。无状态组建性能比较高,没有生命周期函数。UI 组件一般可以作为无状态组件。

使用 Redux-thunk 中间件实现 ajax 数据请求

redux中使用redux-thunk之后可以在action中做异步请求,action可以是一个函数,dispatch接受的action是函数的时候会
自动执行这个action,action这个函数默认接受一个参数dispatch,可以用来提交action。

什么是 Redux 的中间件

redux中间件是在action和store之间,对dispatch方法的封装升级。使得dispatch既可以接受对象,也可以接受函数。

redux data flow

如何使用 React-redux

  1. npm install react-redux –save
  2. store/index.js 引入 { createStore } from redux
  3. 引入 reducer.js
  4. const store = createStore(reducer)
  5. reducer是一个纯函数 export default (state, action) = > {}
  6. todoList 组件中引入 conncect 组件连接组件和 store
  7. index.js 根组件中从react-redux 中引入 Provider
  8. const app = ( < todoList />)
  9. todoList 组件通过 connect 组件把store和组件连接起来
    export default connect(mapStateToPropd,mapDispatchToProps)(TodoList)

react-redux提供了Provider组件,用来绑定store,Provider内部的所有子组件都能够连接store。

Provider的子组件通过react-redux中的connect连接store,写法:
connect(mapStateToProps, mapDispatchToProps)(Component)
mapStateToProps:store中的数据映射到组件的props中;
mapDispatchToProps:把store.dispatch方法挂载到props上;
Component:Provider中的子组件本身;

connect函数返回的是一个容器组件。

使用immutable库避免state被直接改变

  1. immutable库提供一个fromJS方法,可以把一个JS对象转换为immutable(不可变)对象;
  2. 使用immutable.js之后,不能用“.”访问store中的对象,要使用get()方法;
  3. 使用immutable.js之后,修改store中的数据时,要使用set方法;
  4. immutable对象的set方法,会结合之前immutable对象的值和设置的值,返回一个全新的对象,并没有改变原始的state;