React 高级内容
React 的数据视图更新原理
- state 数据
- JSX 模版
- 数据 + 模版 生成虚拟 DOM(虚拟 DOM 就是一个 JS 对象,用它来描述真实 DOM )(损耗了性能)
- 用虚拟 DOM 的结构生成真实的 DOM 来显示
- state 发生变化
- 数据 + 模版 生成新的虚拟 DOM(极大地提升了性能)
- 比较原始虚拟 DOM 和新的虚拟 DOM 的区别(极大地提升了性能)
- 直接操作 DOM,改变上一步中被修改了的的内容
优点:
- 性能提升
- 它使得跨端应用得以实现,React Native。
虚拟 DOM 中的 Diff 算法
问:什么时候会需要比对?
答:数据发生变化的时候,其实就是调用 setState 方法的时候
- setState 方法是异步的,可以把多次 setState 统一到一起,减少 DOM 比对的次数
- 虚拟 DOM 是同级比对的,如果比对有差异,下面级别的就不用比对了,直接把替换下面所有的级别
- 虚拟 DOM 循环的时候,要给定一个唯一的 Key(最好是唯一标识 ID 之类的,不能重复的),不要使用索引作为 Key
Ref 的使用
- ref 可以帮助我们获取 DOM 元素
- 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这个生命周期函数
- 借助 shouldComponentUpdate 可以避免无谓组件render函数的运行,提高性能
1 | // nextProps是新的属性值 |
- 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 | handleToggle() { |
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是视图层框架,把所有数据都放在store之中,每个组件都要从store里拿数据,然后每个组件也要去改store里面的数据,
举例:把这个流程理解成一个图书馆的流程
react compontents: 借书的人
action creators: “要借什么书”这句话(语句的表达,数据的传递)
store: 图书馆管理员(没办法记住所有书籍的存储情况)
reducers: 图书馆管理员的记录本(要借什么书,先查有没有,要还的书查一下放到某个位置);
借书的人~我要借一本书~图书管理员听见~查阅reducers手册~去store找书~把对应的书给借书人;
创建 Redux 的 Store
- npm安装Redux
- 在store文件夹下创建index.js,import { createStore } from ‘redux’
在store文件夹下创建reducer.js
1
2
3
4
5
6const defaultState = {
inputValue:'123'
}
export default (state = defaultState,action) => {
return state;
}index.js中const store = createStore(reducer);
- 在组件中引入,this.state = store.getState()
Action 和 Reducer 的编写
- react首先要改变stroe里的数据,先要派发一个action, action通过dispatch(action)方法传给store
- stroe 把之前的数据和action(previousState,action)传给reducer
- reducer是个函数,它接收了state和action以后做些处理会返回一个新的newState给到store
- 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既可以接受对象,也可以接受函数。
如何使用 React-redux
- npm install react-redux –save
- store/index.js 引入 { createStore } from redux
- 引入 reducer.js
- const store = createStore(reducer)
- reducer是一个纯函数 export default (state, action) = > {}
- todoList 组件中引入 conncect 组件连接组件和 store
- index.js 根组件中从react-redux 中引入 Provider
- const app = (
< todoList /> ) - 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被直接改变
- immutable库提供一个fromJS方法,可以把一个JS对象转换为immutable(不可变)对象;
- 使用immutable.js之后,不能用“.”访问store中的对象,要使用get()方法;
- 使用immutable.js之后,修改store中的数据时,要使用set方法;
- immutable对象的set方法,会结合之前immutable对象的值和设置的值,返回一个全新的对象,并没有改变原始的state;