常见面试题:
1.React组件如何通讯?
2.JSX本质是什么?
3.context是什么?有何用途?
4.shouldComponentUpdate的用途?
5.描述redux单项数据流
6.setState是同步还是异步(场景题)
一、基本使用
1.JSX基本使用
1.1获取变量、插值
1.2 表达式
jsx中不能用if else语句,可以使用三元表达式
1.3子元素
1.4 class
不能写class,要写className
1.5 style样式
把样式保存在一个变量,然后用{}包裹;而下面的{{}},外面的括号表示要包裹一个js变量,里面的括号表示一个对象
1.6原生
1.7 加载组件
2.条件判断
2.1 if else
2.2 三元表达式
2.3逻辑运算符 && ||
3.渲染列表
3.1 map
3.2 key
4.事件
4.1 bind this
方法一、推荐
方法二
方法三:推荐
4.2 关于event参数
????
传递id和title,接收参数时,会在后面追加一个event参数
5.表单
5.1 受控组件
5.2 textarea-使用value
5.3 select-使用value
5.4 check使用checked
5.5 radio
6.组件使用
6.1 props传递数据
父->子:使用props属性
接收:
6.2 props传递函数
接收
6.3 props 类型检查
安装prop-types
:
引入import PropTypes from 'prop-types'
7.setState
7.1 不可变值
例子:
7.1.1 不可变值(函数式编程,纯函数)-数组
注:都不能直接去修改原对象
7.1.2 不可变值-对象
7.2 setState可能是异步更新(也有可能是同步更新)
7.2.1 this.set中setState异步情况:
直接在this.setState
里面用是异步的
7.2.2
setTimeout中setStat同步情况:
而
this.setState
在setTimeout
和自定义的DOM事件中用是同步的
自己定义的DOM事件,setState是同步的:
7.3可能会被合并:传入对象时会被合并,传入函数时不会被
7.3.1 传入对象
//1
7.3.2 传入函数:函数不像对象,不能被合并
8.生命周期
React生命周期分三个阶段:
Mounting:已插入真实 DOM
Updating:正在被重新渲染
Unmounting:已移出真实 DOM
React 为每个状态都提供了两种处理函数,will 函数在进入状态之前调用,did 函数在进入状态之后调用,三种状态共计五种处理函数
此外,React 还提供两种特殊状态的处理函数
常用:
不常用:
9.React高级特性
9.1函数组件
class组件:
函数组件:
1.纯函数,输入
props
,输出JSX
2.没有实例,没有生命周期,没有state
3.不能扩展其他方法
9.2非受控组件
9.2.1 ref、defaultValue 和defaultChecked、手动操作DOM元素
//input defaultValue(通过defaultValue给出一个默认值,变化的值通过ref获取)
//checkbox defaultCheckbox
例子:文件上传
9.2.2 非受控组件-使用场景
1.不许手动操作DOM元素,setState实现不了(setState只能实现前端页面渲染方面的,不能实现交互方面)
2.文件上传
3.某些富文本编辑器,需要传入DOM元素
9.2.3受控组件和非受控组件
答:优先使用受控组件,符合react设计原则;必须操作DOM时,在使用非受控组件,比如文件上传
9.3 Portals传送门
组件默认会按照既定层次嵌套渲染
如何让组件渲染到父组件以外
因为position:fixed是相对于窗口定位的,要放在body下面
使用场景:
1.overflow:hidden
:产生bfc时,父组件会限制自组件的展示,设置portals会使子组件逃离父组件
2.父组件z-index值太小
3.fixed需要放在body第一层级
9.4 context
公共信息(语言、主题)如何传递给每个组件?用props太繁琐,用redux小题大做,因此用context最为合适
创建:
生产:
消费:
此例子没有在Toolbar使用,而是在其子组件
和
中使用:
class组件中的使用方法:首先指定contextType读取当前ThemeContext,或者用
static contextType=ThemeContext
也可以,再用this.context获取theme
,react会网上找最近的theme Provider
而函数组件:函数组件没有实例,通过.Consumer
进行传递
面试时要说明api:创建、生成、消费
9.5 异步组件
9.5.1 import()
9.5.2 React.lazy
9.5.3 React.Suspense
9.6 性能优化
1.shouldComponentUpdate(简称SCU):
//React默认:父组件有更新,子组件则无条件
eg1:
//Footer组件
效果:
注:上面的效果图可知,input输入框和list列表组件有新数据而更新,使得Footer组件没有新数据也被迫更新,这样会造成不合理。
在React逻辑里,默认情况下父组件有更新,子组件也会无条件更新。
怎么性能优化?使用SCU
优化Footer组件:
如果footer组件的数据信息text和之前的一样,就不重复更新
//效果图
eg2:
SCU必须配合不可变值:
注意不可变值,不能用push,会改变原数组,可使用concat
2.PureComponent和memo
class组件:PureComponent,SCU中上线了浅比较
;
函数组件:`memo,函数组件中的
PureComponent`;
浅比较已使用大部分情况(尽量不要做深度比较)
3.inmutable.js
彻底拥抱“不可变值”;
inmutable.js基于共享数据(不是深拷贝),速度好;
有一定学习和迁移成本,按需使用
性能优化-小结:
1).面试重点,涉及react涉及理念
2).SCU PureComponent memo immutable.js
3).按需使用&state层级
9.7 关于组件公共逻辑的抽离:
1) minxin,已被React弃用
2)高阶组件HOC
高阶组件HOC
3) Render Props
高阶组件HOC 基本用法
举例:
就如hooks里面的connect高阶组件:
connect源码
:
Render Props 基本用法
例子:
HOC与Render Props:
HOC:模式简单,但会增加组件层级
Render Props:代码简洁,学习成本较高
二、 Redux使用总结
2.1 基本概念
单项数据流概述:
dispatch(action);
reducer->newState;
subscribe触发通知
2.2 react-redux
四个要点:
mapDispatchToProps.
代码演示:
生产store
消费store:
还有mapStateToProps、mapDispatchToProps:
connect是高阶组件
2.3 异步action
同步时,直接返回action对象;
异步时,需要返回一个函数,函数会接收dispatch参数,再利用fetch进行ajax异步获取数据,再dispatch
2.4 中间件原理
常用的中间件:redux-thunk
、 redux-promise
、redux-saga
、
相对dispatch加入一些业务逻辑处理,需要对dispatch进行改造处理,
3 React-router使用
3.1 路由模式(hash、H5 history)
引入
hash路由
H5 history路由:
使用:
3.2 路由配置(动态路由、懒加载)
跳转路由:
懒加载:
先用import获取异步组件,传进lazy(),就可以直接使用。其中Suspense可以兼容loading情况
4.React原理
4.1 函数式编程
一种编程范式、纯函数、不可变值;
回顾SCU和redux
4.2 vdom和diff
1.只比较同一层级,不跨级比较
2.tag不相同,则直接删掉重建,不再深度比较
3.tag和key,两者都相同,则认为是相同节点,不再深度比较
4.3 JSX本质
1.JSX等同于Vue模板
2.Vue模板不
eg:
//JSX基本用法
//JSX style
//JSX加载组件
//JSX事件
//JSX list
总结:
React.createElement即h函数,返回vnode,
第一个参数可能是组件或者html标签(组件名首字母要大写,html标签不用大写),然后vnode通过patch(elem,vnode)和patch(vnode,newVnode)进行渲染。
4.4 合成事件
所有事件挂载到documnet
上, event
不是原生的,是SyntheticEvent
合成事件对象
从div触发冒泡到document上,document会生成统一的react event,也就是合成事件Synthetic Event对象;在合成事件层,再派发事件,即事件处理函数
注:
1.event是SyntheticEvent,模拟出来DOM事件所有能力
2.event.nativeEvent是原生事件对象
3.所有的事件,都被挂载到document上
4.和DOM事件不一样,和Vue事件不一样
为什么要合成事件机制?
答:1.更好的兼容性和跨平台
2.载到documnet,减少内存消耗,避免频繁解绑
3.方便事件的统一管理(如事务机制)
4.5 setState 和batchUpdate
有时异步(普通使用),有时同步(setTimeout、DOM事件);
有时合并(对象形式),有时不合并(函数形式);
后者比较好理解(像Object.assign),主要讲解前者
setState主流程:
左边:
右边:
那么为什么会出现上面的异步或者同步的不同走向?
而同步:
函数开始都需要设置isBatchingUpdates设置为true,再执行该函数,结束时设置为false。
左边分析:
开始isBatchingUpdates处于true状态,继续执行函数,执行完再isBatchingUpdates设置成false。
右边分析:开始isBatchingUpdates处于true状态,遇到setTimeout异步等待,先执行isBatchingUpdates设置为false,再回到setTimeout函数,此时isBatchingUpdates是false状态,再执行函数程序
因此判断setState是异步还是同步,只需关注isBatchingUpdates是true还是false即可
总结:setState是异步还是同步?
答:1.setState无所谓是异步还是同步2.主要是看能否命中batchUpdate机制
3.判断isBatchingUpdates
那么,哪些能命中batchUpdate机制?
1.生命周期(和它调用的函数)
2.React中注册的是事件(和他调用的函数),比如onclick事件、onchange事件
总之是react可以“管理”的入口
哪些不能命中batchUpdate机制?
答:
React“管不到”的入口:1.setTimeout 、setInterval等(和他调用的函数)
2.自定义的DOM事件(和他调用的函数)
transaction事务机制
定义一个开始的逻辑,再执行该函数体,再定义一个结束的逻辑
例子:
4.6 组件渲染和更新过程
渲染过程?
1.props 和state
2.render()生成vnode
3.patch(elem,vnode)
更新过程?
1.setState(newState)-->dirtyComponents(可能有子组件)
2.render()生成newVnode
3.patch(vnode,newVnode)
更新的两个阶段:
上述的patch被拆分为两个阶段:
1.reconciliation阶段-执行diff算法,纯JS计算
2.commit阶段-将diff结果渲染DOM
如果不分成这两个阶段,可能会有性能问题:
答:首先JS是单线程, 且和DOM渲染共用一个进程;当组件足够复杂,组件更新时计算和渲染都压力大;
同时再有DOM操作新要求(动画,鼠标拖拽等),将卡顿
解决方案:fiber
答:首先将reconciliation阶段进行任务拆分(commit无法拆分);再DOM需要渲染时(window.requestIdleCallback)暂停reconciliation阶段任务片段,空闲时恢复;
面试题:
1.组件之间如何通讯?
答:父子组件 :父给子组件props,子组件给父组件传递函数,让父组件调用;
自定义事件;
Redux和Context:
2.JSX本质是什么?
答:createElement,执行返回vnode,利用patch
3.Context是什么?如何应用?
答:父组件,向其下所有子孙组件传递信息,如一些简单的公共信息:主题色、语言等;简单的用props,复杂的用redux,中间程度的用context
3.SCU性能优化?
答:为了性能优化,但需要配合“不可变值”一起使用,否则会出错
4.setState场景题
前两个都是异步,都是0,前两个合并之后是1,第三个setTimeout同步之后变成2,第四个setTimeout同步之后变成3
5.纯函数?
答:返回一个新值,没有副作用(不会偷偷修改其他值)
重点是不可变值,如arr1=arr.slice()
6.组件生命周期
答:单组件生命周期、父子组件生命周期、注意SCU
7.React发起ajax应该在哪个生命周期?
答:放在componentDidMount,也就是说要放在DOM已经渲染完的周期上才发起ajax,这样才流畅
8.渲染列表,为何使用key?
答:同vue一样,必须用key,且不能是index和random,应该是业务上的id;diff算法中通过tag和key来判断,是否是sameNode,减少渲染次数,提升渲染性能
9.函数组件和class组件区别?
答:纯函数,输入props,输出JSX;没有实例,没有生命周期,没有state;不能扩展其他方法
- 什么是受控组件?
答:表单的值,受state控制;需要自行监听onChange,更新state;对比非受控组件;
11.如何使用异步组件?
答:加载大组件;路由懒加载
12.多个组件有公共逻辑,如何抽离?
答:高阶组件;Render Props;mixin已被React废弃
13.redux如何进行异步请求?
答:使用异步action;如redux-thunk
14.react-router如何配置懒加载
- PureComponent有何区别?
答:实现了浅比较的SCU,性能优化,结合不可变值使用
16.React事件和DOM事件的区别
答:所有的事件是挂载到document上,event不是原生的,是SyntheticEvent合成事件对象;dispatchEvent机制
17.React性能优化?
答:1.渲染列表时加key
2.自定义事件、DOM事件及时销毁
3.合理使用异步组件
4.减少函数bind this的次数
5.合理使用SCU PureComponent和memo
6.合理使用不可变值Immutable.js
7.webpack层面的优化
8.前端通用的性能优化,如图片懒加载
9.使用SSR
18.React和Vue的区别
答:共同点:1).都支持组件化;2)都是数据驱动视图;3)都使用vdom操作DOM;
4)React使用JSX拥抱JS,Vue使用模板拥抱html
5)React函数式编程,vue声明式编程
6)React更多需要自力更生,vue把想要的都给你