1.react基础知识
1.react-dom
BrowserRouter: 利用h5 Api实现路由切换;
HashRouter: 利用hash实现路由切换;
Suspense: 用来优化页面加载,页面加载时用fallback渲染等待加载组件;
2.react生命周期
第一阶段:装载阶段
-
constructor() -
render() -
componentDidMount()
第二阶段:更新阶段
-
shouldComponentUpdate() -
render() -
componentDidUpdate()
第三阶段:卸载阶段
-
componentWillUnmount()
constructor生命周期:
-
当react组件实例化时,是第一个运行的生命周期; -
在这个生命周期中,不能使用this.setState(); -
在这个生命周期中,不能使用副作用(调接口、dom操作、定时器、长连接等); -
不能把props和state交叉赋值;
componentDidMount生命周期:
-
相当于是vue中的mounted; -
它表示DOM结构在浏览器中渲染已完成; -
在这里可以使用任何的副作用;
shouldComponentUpdate(nextProps,nextState)生命周期:
-
相当于一个开关,如果返回true则更新机制正常执行,如果为false则更新机制停止; -
在vue中是没有的; -
存在的意义:可以用于性能优化,但是不常用,最新的解决方案是使用PureComponent; -
理论上,这个生命周期的作用,用于精细地控制声明式变量的更新问题,如果变化的声明式变量参与了视图渲染则返回true,如果被变化的声明式变量没有直接或间接参与视图渲染,则返回false;
componentDidUpdate生命周期:
-
相当于vue中的updated(); -
它表示DOM结构渲染更新已完成,只发生在更新阶段; -
在这里,可以执行大多数的副作用,但是不建议; -
在这里,可以使用this.setState(),但是要有终止条件判断。
componentWillUnmount生命周期:
-
一般在这里清除定时器、长连接等其他占用内存的构造器;
render生命周期:
-
render是类组件中唯一必须有的生命周期,同时必须有return(return 返回的jsx默认只能是单一根节点,但是在fragment的语法支持下,可以返回多个兄弟节点); -
Fragment碎片写法: <React.Fragment></React.Fragment> 简写成<></>; -
return之前,可以做任意的业务逻辑,但是不能使用this.setState(),会造成死循环; -
render()在装载阶段和更新阶段都会运行; -
当render方法返回null的时候,不会影响生命周期函数的正常执行。
forceUpdate: 页面强制更新,不经过 shouldComponentUpdate();
componentWillReceiveProps: 在子组件内,将要接收props调用(第一次不会调用,更新后才开始调用,可以接收参数props,参数是更新后的值);
unmountComponentAtNode: 组件的卸载(ReactDom.unmountComponentAtNode(gocument.getElementById('...')));
react新的生命周期 - react-17.0.1开始采用
- getDerivedStateFromProps:
- getSnapshotBeforeUpdate:
3.react-router
一般组件与路由组件: 路由组件就会有history等属性, 默认为undefined
路由组件属性:
Link: 用来页面跳转,没有高亮的效果。
NavLink: 用来页面跳转,可以实现高亮的效果,通过activeClassName指定类名, 与defaultChecked类似。
Outlet: 在嵌套路由, 在父级内用来占位, 显示子路由;
Navigate: 路由重定向;
useNavigate: 用来跳转并传值;
useLocation: 用来接收跳转传过来的值;
Switch组件: 用来路由中做单独匹配(模糊匹配时,从上到下只匹配一个路由),提高效率。
exact属性: 路由加上后会取消模糊查询机制,变成精准匹配
Redirect组件: 当路由找不到时,做处理的组件
props.children: 父组件标签体内的内容,可以在子组件中的props.childern中找到
多层路由样式丢失解决办法:
路由传参: params传参,search传参,state传参
编程式路由跳转: 就是push和replace用法,push会记录路由记录, replace是直接替换掉上一个记录
withRouter : 能够接收一般组件,并给一般组件加工上路由组件的属性,让一般组件也具备路由跳转的功能属性。
BrowerRouter和HashRouter区别:
4.redux
createStore: 用来将state存入store;
reducer(preSatate, action): 传入之前的状态, 传入动作对象, 返回一个新的状态;就是处理状态的纯函数;
Provider: 跨组件传值,避免父子组件层层传递;向子组件暴漏数据(生产者);
Consumer: 跨组件传值,避免父子组件层层传递;接收父组件传值(消费者);
createContext: 解决无需层级关系传递,Provider传递,Consumer接收;
useContext: 使用useContext接受上下文,因为传入的是对象,则接受的也应该是对象;
store.getState: 获取状态;
store.dispath(type, data): 触发的条件和值;
store.subscribe: 检测store中数据的变化后render页面;
connect(参数, 方法)(UI组件): 容器组件,用来链接ui组件和redux的,ui组件只能用来展示,所以必须在外层包裹一个容器组件做数据的处理工作;(注意: 因为react-redux帮做处理了,所以store和其中的state和dispatch就可以直接拿到了)
connect(参数对象, {actions...})(Ui组件): react-redux帮忙做了diapatch处理
combineReducers: 合并的总的reduers的集合,合并后是一个总和的集合对象;
纯函数: redux中数组的处理不能用push和unshift的原因,不是纯函数,改变了原来的数组的引用类型数组的指向,改变了原数组,不能用,所以只能用[...oldArr, data];用[...oldArr],原本的oldArr没有改变。
5.react-css
styled-components: css in js方式的一种;
antd按需引入: 参照antd官网,3.xxx版本的详细文档去一步步走即可;
antd样式自定义主题:
6.react-hooks
React 一直提倡使用函数组件,但是有一些功能只有类组件具备,比如函数组件没有实例,没有生命周期函数,而 React 16.8 提出的 Hooks 概念可以在不编写 Class 的情况下,使用 React 特性。凡是 use 开头的 React API 都是 Hooks。
Hooks 使用的注意事项:只能在函数内部的最外层调用 Hook,且只能在react的函数组件中调用,不要在其他javascript函数中调用。不要在循环,条件判断或者子函数中调用。只有 Hook 的调用顺序保持一致,React 才能正确地将内部 state 和对应的 Hook 进行关联。React Hooks 内部是链表结构的,如果不按照顺序书写或者某个 useState 没有执行,就会导致指针移动出错,数据存取出错。
-
useDispatch: 向store传递方法, 与redux搭配使用; -
useSelector: 子组件用来访问父组件state中的数据,与redux搭配使用; -
useRef: 用来获取ref绑定的dom对象,获取的对象只有个current属性,只在函数式组件用,与createRef的写法一致; -
useState: useState 通过在函数组件里调用它来给组件添加一些内部state(函数组件是没有state的,class组件有)。React会在重复渲染时保留这个state。useState会返回一对值:当前状态和一个让你更新它的函数,你可以在事件处理函数中或其他一些地方调用这个函数。它类似 class 组件的this.setState,但是它不会把新的 state 和旧的 state 进行合并。 -
useEffect: 可以看作是componentDidMount,componentDidUpdate,componentWillUnmount三个的组合,这个函数就是用来处理"副作用"的, 举个通俗一点的例子, 假如感冒了本来吃点药就没事了, 但是吃了药发现身体过敏了,而这个"过敏"就是副作用。放到React中,本来只是想渲染DOM展示到页面上,但除了DOM之外还有数据,而这些数据必须从外部的数据源中获取,这个"获取外部数据源"的过程就是副作用。useEffect使用时有以下4种情况: 1. 不传递 useEffect不传递第二个参数会导致每次渲染都会运行useEffect。然后,当它运行时, 它获取数据并更新状态。然后,一旦状态更新,组件将重新呈现, 这将再次触发useEffect,这就是问题所在。 useEffect(()=>{ console.log(props.number) setNumber(props.number) }) //所有更新都执行 2. 传递空数组 useEffect(()=>{undefined console.log(props) },[]) //仅在挂载和卸载的时候执行 3. 传递一个值 useEffect(()=>{undefined console.log(count) },[count]) //count更新时执行 4. 传递多个 const Asynchronous : React.FC=({number})=>{ const [number2,setNumber2] = useState(number); useEffect(()=>{ console.log(number) setNumber2(number) },[number,setNumber2]) //监听props对象number的更改 //setNumber2是useState返回的setter,所以不会在每次渲染时重新创建它, //因此effect只会运行一次 } 5. 传递props的对象 传递的useState返回的setter 6. return 方法 const timer = setInterval(() => {undefined setCount(count + 1) }, 1000) // useEffect方法的第一个参数是一个函数,函数可以return一个方法, //这个方法就是在组件销毁的时候会被调用 useEffect(() => { return () => { clearInterval(timer) } }, []) -
useLayoutEffect: useLayoutEffect有DOM操作的副作用,在DOM更新之后执行和useEffet类似,但是执行时机不同,useLayoutEffect在DOM更新之后执行,useEffect在render渲染结束后执行,也就是说useLayoutEffect比useEffect先执行,这是因为DOM更新之后,渲染才结束或者渲染还会结束。useLayoutEffect执行比较useEffect快,useEffect每次都是完整流程,而useLayoutEffect在vdom后先不渲染,先更新,最后只渲染一次。 -
useMemo: 用来做缓存用。useMemo使用场景,比如有两个变量(依赖项),只需要在其中一个变量变化时发生变化,否则拿缓存的值;或者其中另一个变量的变化不需要引起重新计算时使用。该属性类似于vue中的计算属性,有返回值。const memoizedValue =useMemo(callback,array); callback是一个函数用于处理逻辑 array 控制useMemo重新执行的数组,array改变时才会重新执行useMemo 不传数组,每次更新都会重新计算 空数组,只会计算一次 依赖对应的值当对应的值发生变化时才会重新计算(可以依赖另外一个useMemo 返回的值) useMemo的返回值是一个记忆值,是callback的返回值
8.useCallback:与useMemo类似;useMemo与useCallback相同,接收一个函数作为参数,也同样接收第二个参数作为依赖列表;useCallback是对传过来的回调函数优化,返回的是一个函数。
被route包裹的组件,可以直接使用props进行路由相关操作,但是没有被route包裹的组件只能用withRouter高阶组件修饰或者使用hooks进行操作
9.useHistory: 跳转路由;
10.useLocation: 得到url对象;
11.useParams: 得到url上的参数;
useRef和useImperativeHandle以及React.forwardRef:
7.redux和hooks搭配使用流程
【useState】-> 【useReducer】-> 【useSelector、useDispatch】 通过useSelector、useDispatch等方法,我们可以用Hooks方法完成Redux的功能,Hooks和Redux之间没有替代关系,应该更好地共存和融合。 React.memo 为高阶组件。它与 React.PureComponent 非常相似,但它适用于函数组件,但不适用于 class 组件。
8.react高阶组件
React.memo: 适用于函数组件,但不适用于 class 组件;React.memo()使用场景就是纯函数组件频繁渲染props;React.memo 仅检查 props 变更,且其实现中拥有 useState 或 useContext 的 Hook,当 context 发生变化时,它仍会重新渲染;其实就是在实现shouldComponentUpdate生命周期。React.PureComponent: 在class组件中使用。React.PureComponent 与 React.Component 唯一的区别在于 Rect.Component 没有实现 shouldComponentUpdate(), 而 React.PureComponent 中以浅层对比 props 和state 的方式来实现了该函数。withRouter:withRouter的作用就是, 如果我们某个东西不是一个Router, 但是我们要依靠它去跳转一个页面, 比如点击页面的logo,返回首页。, 这时候就可以使用withRouter来做.withRouter, 作用是将一个组件包裹进Route里面, 然后react-router的三个对象history, location, match就会被放进这个组件的props属性中。被route包裹的组件,可以直接使用props进行路由相关操作,但是没有被route包裹的组件只能用withRouter高阶组件修饰或者使用hooks进行操作
9.react中间件
applyMiddleware: 将所有中间件组成一个数组,依次执行;
redux-thunk: redux-thunk主要对异步运用中间件做一些处理,因为reducer应该是一个纯函数,不能有副作用,只能根据action对state进行更新,因此不能在此发出网络请求。那么借助redux-thunk来在发出action至reducer处理之间借助middleware来进行处理。
10.react分层
State: 数据状态
Reducer:纯函数,只承担计算 State 的功能,不合适承担其他功能,也承担不了,因为理论上,纯函数不能进行读写操作。
View:与 State 一一对应,可以看作 State 的视觉层,也不合适承担其他功能。
Action:存放数据的对象,即消息的载体,只能被别人操作,自己不能进行任何操作。
11.react类型检查
PropTypes检测基础数据类型:
- optionalArray: PropTypes.array,
- optionalBool: PropTypes.bool,
- optionalFunc:
PropTypes.func, - optionalNumber: PropTypes.number,
- optionalObject: PropTypes.object,
- optionalString: PropTypes.string,
- optionalSymbol: PropTypes.symbol,
arrOf和objectOf多重嵌套类型检测:
// An array of a certain type
optionalArrayOf: PropTypes.arrayOf(PropTypes.number),
// An object with property values of a certain type
optionalObjectOf: PropTypes.objectOf(PropTypes.number),
//示例
static propTypes = {
todoList:PropTypes.arrayOf(PropTypes.shape({
id:PropTypes.string.isRequired,
text:PropTypes.string
}))
}
shape检测不同对象的不同属性的不同数据类型:
// An object taking on a particular shape
optionalObjectWithShape: PropTypes.shape({
optionalProperty: PropTypes.string,
requiredProperty: PropTypes.number.isRequired
}),
//示例
static propTypes = {
object:PropTypes.shape({
name:PropTypes.string,
age:PropTypes.number
})
}
12.虚拟dom实现原理
虚拟dom是用js模拟一颗dom树,放在浏览器内存中,相当于在js和真实dom中加了一个缓存,利用dom diff算法避免了没有必要的dom操作,从而提高性能。
虚拟dom优点:
- 虚拟DOM具有批处理和高效的Diff算法,最终表现在DOM上的修改只是变更的部分,可以保证非常高效的渲染,优化性能;
- 虚拟DOM不会立马进行排版与重绘操作,对虚拟DOM进行频繁修改,最后一次性比较并修改真实DOM中需要改的部分;
- 虚拟 DOM 有效降低大面积真实 DOM 的重绘与排版,因为最终与真实 DOM 比较差异,可以只渲染局部;
虚拟dom缺点:首次渲染大量DOM时,由于多了一层虚拟DOM的计算,会比innerHTML插入慢;
React组件的渲染过程:
- 使用JSX编写React组件后所有的JSX代码会通过Babel转化为 React.createElement执行;
- createElement函数对 key和 ref等特殊的 props进行处理,并获取 defaultProps对默认 props进行赋值,并且对传入的子节点进行处理,最终构造成一个 ReactElement对象(所谓的虚拟 DOM)。
- ReactDOM.render将生成好的虚拟 DOM渲染到指定容器上,其中采用了批处理、事务等机制并且对特定浏览器进行了性能优化,最终转换为真实 DOM。
虚拟DOM的组成——ReactElementelement对象结构:
- type:元素的类型,可以是原生html类型(字符串),或者自定义组件(函数或class)
- key:组件的唯一标识,用于Diff算法,下面会详细介绍
- ref:用于访问原生dom节点
- props:传入组件的props,chidren是props中的一个属性,它存储了当前组件的孩子节点,可以是数组(多个孩子节点)或对象(只有一个孩子节点)
- owner:当前正在构建的Component所属的Component
- self:(非生产环境)指定当前位于哪个组件实例
- _source:(非生产环境)指定调试代码来自的文件(fileName)和代码行数(lineNumber);
13. state和props区别
- props是从外部传入组件的参数,一般用于父组件向子组件通信,在组件之间通信使用;state一般用于组件内部的状态维护,更新组建内部的数据,状态,更新子组件的props等
- props不可以在组件内部修改,只能通过父组件进行修改;state在组件内部通过setState修改;
14. 单向数据流和双向绑定原理
react的单向数据流是指只允许父组件向子组件传递数据,子组件绝对不能修改父组件传的数据,如果想要修改数据,则要在子组件中执行父组件传递过来的回调函数,提醒父组件对数据进行修改。数据单向流让所有的状态改变可以追溯,有利于应用的可维护性;
angular中实现了双向数据绑定,代码编写方便,但是不利于维护
15. react组件信息传递
- (父组件)向(子组件)传递信息 : porps传值
- (父组件)向更深层的(子组件) 进行传递信息 : context
- (子组件)向(父组件)传递信息:callback事件
- 没有任何嵌套关系的组件之间传值(比如:兄弟组件之间传值): 利用共同父组件context通信、自定义事件
- 利用react-redux进行组件之间的状态信息共享 : 组件间状态信息共享:redux、flux、mobx等
- 发布订阅: 利用第三方库, PubSubJs
16. jsx语法规则
17. 类相关基本知识复习
18. 函数式组件与类式组件
函数式组件的定义
类式组件
复杂组件:类组件中,有state就是复杂的,否则就是简单组件;或者说有状态的就是复杂组件。
19. 组件的四大属性(state, props, refs: 在组件实例组件对象的构造属性; context再说)
类组件中的属性,函数式组件需要用到hooks支持
- 初始化state
- 修改state事件
- setState用法
- 修改state事件的简化版(es6箭头函数,this向外层查找)
- 对props中的属性进行限制的简写方法(
static的用法) 函数式组件拿不到state和refs,但是可以拿到props;除非利用hooks- refs的基础用法(react16.8开始已经废弃, string类型的refs影响效率)
- 回调函数形式的refs(利用es6的箭头函数,()和{}都可以省略, 所以只有了一个{};
页面更新时调两次,第一次为null,第二次才是真正的节点) - 内联函数的refs(
不会随着更新时频繁调用) - React.createRef方式创建结点(目前最推荐的一种方式了)
20. react中事件处理
当事件绑定的元素正是你要操作的元素时,可以省略ref绑定,通过event.target获取到当前元素(其实事件的触发是通过事件委托,委托元素的上级元素进行处理的,即冒泡)- 非受控组件(点击button的时候会执行handleSubmit事件,但是事件是绑定在form上的,承接上面所说事件委托)
- 受控组件(
推荐, 没有ref, 尽量减少了ref绑定,提高效率; 事件的双向绑定) - 高阶组件-柯里化函数([dataType]:因为字符串形式的不会转成相应的key, 所以用[]包裹一下)
- 高阶组件-不用柯里化函数()
21. todoList小案例总结
22. redux开发者工具
2.react扩展
1. setState
setState触发更新是异步的,函数式的话在函数体内能够获取到最新的值
2. lazyLoad
3. useState
4. useEffect
5. refEffect
6. context
7. pureComponent
8. render props