原文链接:https://github.com/helloyoucan/knowledge
React
1.概念特点
- react中某个组件的状态发生改变,react会触发该组件和所有后代组件重新渲染,但不会全部丢弃上一次的渲染结果,会通过diff去比较两次虚拟dom最后更新到真实的dom上。若组件树过大,diff开销也大,可通过shouldComponentUpdate优化。
- React将整个DOM副本保存为虚拟DOM
- 使用 Virtual DOM 更新真正的DOM,提高效率和速度
2.JSX
- JavaScript的语法扩展,模板语言
- 生成React元素
- 组件名大写(让react识别是组件还是HTML元素)
3.组件生命周期v16.4
constructor()
static getDerivedStateFromProps(props, state) :object|null #初次渲染和后续更新都会调用,返回对象更新state或返回null不作任何更新
shouldComponentUpdate():boolean
render()
getSnapshotBeforeUpdate(prevProps, prevState): snapshot |null #最近一次渲染输出调之前用,可传递参数(snapshot )到componentDidUpdate
componentDidMount()
componentDidUpdate(prevProps, prevState, snapshot)
componentWillUnmount()
当渲染过程,生命周期,或子组件的构造函数中抛出错误时,会调用如下方法:
static getDerivedStateFromError() #回退UI,显示错误的UI
componentDidCatch() #记录错误
<img src="/images/react/生命周期.png" style="height:600px"/>
4.setState机制
React 是通过管理状态来实现对组件的管理,即使用 this.state 获取 state,通过 this.setState() 来更新 state,当使用 this.setState() 时,React 会调用 render 方法来重新渲染 UI。
- setState通过一个队列机制来实现state更新;
- 当执行setState时,会将需要更新的state浅合并后放入队列状态,不会立即更新;
- 队列机制可以高效地批量更新state;
- 直接修改state的值,则不会放入状态队列,下一次调用setState对状态队列进行合并时,之前直接对this.state的修改将会被忽略,造成无法预知的错误;
- React通过状态队列机制实现了 setState 的异步更新,避免重复的更新 state。
- 由React引发的事件处理(比如onClick),调用setState不会同步更新this.state;
- 除此之外(绕过React通过addEventListener直接添加的事件处理函数、setTimeout/setInterval产生的异步调用),setState调用会同步执行this.state;
5.如何使用样式
- 外部样式表
- 内联样式
- 定以对象传递给style属性
6.组件类型
- 函数/无状态/展示组件
- 类组件
- 受控组件 #表单元素依赖于状态,表单元素需要默认值实时映射到状态的时候,就是受控组件
- 非受控组件 #非受控组件即不受状态的控制,获取数据就是相当于操作DOM
- 容器组件 # 处理获取数据、订阅 redux 存储等的组件,包含展示组件和其他容器组件
- 高阶组件 #高阶组件是将组件作为参数并生成另一个组件的组件
7.PropTypes
- 类型检查工具
- 定义默认的props和prop类型
8.状态更新
this.setState({name:"some name"})
// state和props的更新是异步的
this.setState((state, props) => {
name: state.name + props.years
});
9.context
(对标vue的provide/inject)
- 子孙组件之间共享数据
- 将props传递给组件树(中间组件不需要传这些props)
10.Render Props
(对标vue的slot作用域)
- render prop 的组件接受一个函数,函数返回React元素并调用它(不是实现自己的渲染逻辑)
- 告知组件需要渲染什么内容的函数prop在技术上可被称render prop
<Mouse children={mouse => (
<p>鼠标的位置是 {mouse.x},{mouse.y}</p>
)}/>
11.Redux
- 基于flux的状态管理库
- 简化react中的单向数据流
- 将状态管理完全从react中抽象出来
何如使用
组件连接到redux,访问redux时,需要
dispatch
(派出)一个包含id
和payload
(负载,也就是传参,可不传)的action
,action将其转发给
Reducer`reducer
收到action
时,通过switch...case
语法比较action
中的type
。匹配时,更新对应的内容返回新的state
Redux
状态更改时,连接到Redux
的组件接收新的状态作为props
。组件接收到新的props
,进入更新阶段重新渲染UI。-
下图为简单的工作过程
<img src="/images/react/Redux.png" style="height:300px;"/>
Redux循环细节
<img src="/images/react/Redux循环细节.png" style="height:350px;"/>
-
Action # 一个简单的json对象
//action { type:"",//类型 payload:{}//可选,用于传参 }
-
Action Creators #创建Actions的函数,使得派发action时不需要重复写每个action
export function ActionName(data){ return { type:'', payload:data } }
-
Reducers #纯函数,将action和当前state作为参数,更新state和return新的state。无副作用,不改变state,返回新的state。
export default function nameReducer(state=[],action){ switch(action.type){ case "TEST":return Objact.assign({},state,{name:action.payload}); default: return state } }
组件与redux连接
- content和bindActionCreators来自redux
- mapStateToProps #将state映射到props的函数,订阅state的方式
- mapDispatchToProps #将action creators绑定到props的函数。使用this.props.actions.xxx()派发动作
// import connect
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
// import action creators
import * as userActions from '../../../actions/userActions';
export class User extends React.Component {
handleSubmit() {
// dispatch an action
this.props.actions.sendEmail(this.state.email);
}
}
// you are mapping you state props
const mapStateToProps = (state, ownProps) => ({user: state.user})
// you are binding your action creators to your props
const mapDispatchToProps = (dispatch) => ({actions: bindActionCreators(userActions, dispatch)})
export default connect(mapStateToProps, mapDispatchToProps)(User);
12.路由
react-router-dom
- BrowserRouter和HashRouter是路由器
- Route用于路由匹配
- Link用于创建连接,渲染为锚标记
- NavLink突出显示当前活动连接的特殊连接
- Switch非必需,用于组合路由
- Redirect重定向
13.Fragments
- 类似vue的template标签
//react
<React.Fragment></React.Fragment>
//vue
<template></template>
14.Portals(传送门)
(对标vue利用$el将组件插入到其它地方)
- 用于将子组件渲染到其它地方
- 类类似vue将$el挂载在其它元素上
15.提高性能
- 适当使用shouldComponentUpdate,避免子组件不必要的渲染
- 使用create-react-app构建项目,已经配置好一些优化
- 不可变性是提高性能的关键。不对数据进行修改,在现有集合的基础上创建新的集合,尽可能的复制,从而提高性能
- 显示列表和表格时使用key
- 代码分离,将代码插入到单独的文件,只加载模块或部分所需的代码。
16.API调用
-
使用redux时,可配合redux-thunk中间件
import apiservice from '../services/apiservice'; export function ActionName(data){ return { type:'', payload:data } } export function getXXXAPI(datajson) { return function(dispatch) { return apiservice.callAPI(datajson).then(data => { dispatch(ActionName(data)); }); } }
<img src="/images/react/Redux循环细节+API.png" style="height:350px;"/>
17、Hook
Hook是一些可以在函数组件里“钩入”React state及生命周期等特性的函数。(不能在class组件中使用)
特点
- 将(复杂)组件中相互关联的部分拆分成更小的函数(比如设置订阅或请求数据)
- 在非class组件的情况下可以使用更多的React特性
Hook
- useState #返回当前状态和一个更新它的函数
- useEffect #给函数组件增加操作副作用的能力(
- 第一个参数是函数,第二个参数传入state,指定在state改变时才更新
- 完成对DOM的更改后调用(第一次渲染和每次更新后)
- 与componentDidMount、componentDidUpdate、componentWillUNmount具有相同的用途(被合成一个API)
- (可返回一个函数来指定如何“清除”副作用)
使用规则
- 只能在函数最外层调用Hook,不要在循环、条件判断或者子函数中调用。
- 只能在React的函数组件中调用Hook。
- 可以在自定义Hook中调用Hook
自定义Hook
重用状态逻辑(目前的主流方案:高阶组件和render props),可在不正经组件的情况下达到目的。实际上是一个函数。