1、说一下React
React是Facebook 开发的前端JavaScript库
V层:react并不是完整的MVC框架,而是MVC中的C层
虚拟DOM:react引入虚拟DOM,每当数据变化通过reactdiff运算,将上一次的虚拟DOM与本次渲染的DOM进行对比,仅仅只渲染更新的,有效减少了DOM操作
JSX语法:js+xml,是js的语法扩展,编译后转换成普通的js对象
组件化思想:将具有独立功能的UI模块封装为一个组件,而小的组件又可以通过不同的组合嵌套组成大的组件,最终完成整个项目的构建
单向数据流:指数据的流向只能由父级组件通过props讲数据传递给子组件,不能由子组件向父组件传递数据
要想实现数据的双向绑定只能由子组件接收父组件props传过来的方法去改变父组件数据,而不是直接将子组件数据传给父组件
生命周期:简单说一下生命周期:Mounting(挂载)、Updateing(更新)、Unmounting(卸载)
2、什么是JSX?为什么浏览器无法读取JSX
JSX 是JavaScript XML 的简写,是 React 使用的一种文件
它利用 JavaScript 的表现力和类似 HTML 的模板语法
使得 HTML 文件非常容易理解。此文件能使应用非常可靠,并能够提高其性能
浏览器只能处理 JavaScript 对象,而不能读取常规 JavaScript 对象中的 JSX
所以为了使浏览器能够读取 JSX,首先,需要用Babel转换器将 JSX 文件转换为 JavaScript 对象,然后再将其传给浏览器
3、React与Angular有何不同?
react是Facebook出品,angular是Google
react只有MVC中的C,angular是MVC
react使用虚拟DOM,angular使用真实DOM
react是单项数据绑定,angular是双向数据绑定
4、react生命周期函数
(1)Mounting挂载阶段
constructor()
componentWillMount()组件挂载到页面之前
render()创建虚拟DOM,进行diff运算,更新DOM树。不可进行setState()
componentDidMount()组件挂载到页面之后,可以在此请求数据
(2)Updateing更新阶段
componentWillReceiveProps()父级数据发生变化
shouldComponentUpdate()
性能优化:这个函数只返回true或false,表示接下来的组件是否需要更新(重新渲染)
返回true就是紧接着以下的生命周期函数,返回false表示组件不需要重新渲染,不再执行任何生命周期函数(包括render)
componentWillUpdate() 组件更新之前,不可进行setState() 会导致函数调用shouldComponentUpdate从而进入死循环
render()
componentDidUpdate()组件更新之后
(3)Unmounting卸载阶段
componentWillUnmount 组件卸载和销毁之前立刻停用
可以在此销毁定时器,取消网络请求,消除创建的相关DOM节点等
5、shouldComponentUpdate是做什么的,(react性能优化是哪个周期函数?)
shouldComponentUpdate 这个方法用来判断是否需要调用render方法重新绘制dom
因为DOM的描绘非常消耗性能,如果我们能在shouldComponentUpdate 方法中能够写出更优化的 dom diff 算法,可以极大的提高性能
6、为什么虚拟 DOM 会提高性能? 说下他的原理
虚拟 dom 相当于在 js 和真实 dom 中间加了一个缓存,利用 dom diff 算法避免了没有必要的 dom 操作,从而提高性能
Virtual DOM 工作过程有三个简单的步骤
1)每当底层数据发生改变时,整个 UI 都将在 Virtual DOM 描述中重新渲
2)然后计算之前 DOM 表示与新表示的之间的差异
3)完成计算后,将只用实际更改的内容更新 real DOM
7、调用setState之后发生了什么?
当调用setState后,新的 state 并没有马上生效渲染组件,而是,先看执行流中有没有在批量更新中
如果有,push到存入到dirtyeComponent中,如果没有,则遍历dirty中的component,调用updateComponent,进行state或props的更新
然后更新UI,react进行diff运算,与上一次的虚拟DOM相比较,进行有效的渲染更新组件
8、react diff 原理
diff(翻译差异):计算一棵树形结构转换成另一棵树形结构的最少操作
1)把树形结构按照层级分解,只比较同级元素
2)给列表结构的每个单元添加唯一的 key 属性,方便比较
3)React 只会匹配相同 class 的 component(这里面的 class 指的是组件的名字)
4)合并操作,调用 component 的 setState 方法的时候, React 将其标记为 dirty.到每一个事件循环结束, React 检查所有标记 dirty 的 component 重新绘制
5)选择性子树渲染。开发人员可以重写 shouldComponentUpdate 提高 diff 的性能
9、setState 何时同步何时异步?
1)setState 只在合成事件(react为了解决跨平台,兼容性问题,自己封装了一套事件机制,代理了原生的事件,像在jsx中常见的onClick、onChange这些都是合成事件)和钩子函数(生命周期)中是“异步”的,在原生事件和 setTimeout 中都是同步的
2)setState的“异步”并不是说内部由异步代码实现,其实本身执行的过程和代码都是同步的,只是合成事件和钩子函数的调用顺序在更新之前,导致在合成事件和钩子函数中没法立马拿到更新后的值,形式了所谓的“异步”,当然可以通过第二个参数 setState(partialState, callback) 中的callback拿到更新后的结果
3)setState 的批量更新优化也是建立在“异步”(合成事件、钩子函数)之上的,在原生事件和setTimeout 中不会批量更新,在“异步”中如果对同一个值进行多次 setState , setState 的批量更新策略会对其进行覆盖,取最后一次的执行,如果是同时 setState 多个不同的值,在更新时会对其进行合并批量更新
10、react渲染机制
1)当页面一打开,就会调用render构建一棵DOM树
2)当数据发生变化( state | props )时,就会再渲染出一棵DOM树
3)此时,进行diff运算,两棵DOM树进行差异化对比,找到更新的地方进行批量改动
11、React中refs 的作用是什么?
Refs 是 React 提供给我们的安全访问 DOM 元素或者某个组件实例的句柄
我们可以为元素添加 ref 属性然后在回调函数中接受该元素在 DOM 树中的句柄
该值会作为回调函数的第一个参数返回
12、组件的状态(state)和属性(props)之间有何不同
State 是一种数据结构,用于组件挂载时所需数据的默认值。State 可能会随着时间的推移而发生突变,但多数时候是作为用户事件行为的结果
Props(properties 的简写)则是组件的配置。props 由父组件传递给子组件,并且就子组件而言,props 是不可变的
组件不能改变自身的 props,但是可以把其子组件的 props 放在一起(统一管理)
13、在构造函数中调用 super(props) 的目的是什么
在 super() 被调用之前,子类是不能使用 this 的,在 ES2015 中,子类必须在 constructor 中调用 super()。传递 props 给 super() 的原因则是便于(在子类中)能在 constructor 访问 this.props
14、为什么在componentDidMount()中请求数据
componentDidMount方法中的代码,是在组件已经完全挂载到网页上才会调用被执行,所以可以保证数据的加载
15、何为受控组件(controlled component)
在HTML 中,类似 , 和 这样的表单元素会维护自身的状态,并基于用户的输入来更新,当用户提交表单时,
前面提到的元素的值将随表单一起被发送,但在 React 中会有些不同,包含表单元素的组件将会在 state 中追踪输入的值,并且每次调用回调函数时
如 onChange 会更新 state,重新渲染组件,一个输入表单元素,它的值通过 React 的这种方式来控制,这样的元素就被称为”受控元素”
16、何为高阶组件(higher order component)
高阶组件是一个以组件为参数并返回一个新组件的函数。HOC 运行你重用代码、逻辑和引导抽象,最常见的可能是 Redux 的 connect 函数
除了简单分享工具库和简单的组合,HOC 最好的方式是共享 React 组件之间的行为
如果你发现你在不同的地方写了大量代码来做同一件事时,就应该考虑将代码重构为可重用的 HOC
17、React中的状态是什么?它是如何使用的?
状态是 React 组件的核心,是数据的来源,必须尽可能简单。基本上状态是确定组件呈现和行为的对象。与props 不同,它们是可变的,并创建动态和交互式组件。可以通过 this.state() 访问它们
18、解释 React 中 render() 的目的
每个React组件强制要求必须有一个 render()。它返回一个 React 元素,是原生 DOM 组件的表示
如果需要渲染多个 HTML 元素,则必须将它们组合在一个封闭标记内,例如 、、
此函数必须保持纯净,即必须每次调用时都返回相同的结果
19、理解“在React中,一切都是组件”这句话
组件是 React 应用 UI 的构建块。这些组件将整个 UI 分成小的独立并可重用的部分
每个组件彼此独立,而不会影响 UI 的其余部分
20、react父子组件之间如何通信,兄弟组件呢?
父级传递子级:把数据挂载子组件的属性上,子组件通过this.props来接收父组件的数据
子级传递父级:父级需要定义一个修改数据的方法,把修改数据的方法传给子组件,当子组件需要修改父级数据时,调用父级传过来的修改方法
兄弟组件传递:属于同一个父级,父组件分别和这两个组件传递。比如子组件A操作执行父组件方法,父组件进行修改,然后把信息传给子组件B
21、请列举定义react组件的中方法
1)函数式定义的无状态组件
2)es5原生的方式 React.createClass方式
3)es6中extends React.Component定义的组件
22、react中component和pureComponent区别是什么?
PureComponent自带通过props和state的浅对比来实现 shouldComponentUpate(),而Component没有
比于Component,PureCompoent的性能表现将会更好
23、什么是无状态组件,与有状态组件的区别
无状态组件主要用来定义模板,接收来自父组件props传递过来的数据,使用{props.xxx}的表达式把props塞到模板里面
有状态组件主要用来定义交互逻辑和业务数据,使用{this.state.xxx}的表达式把业务数据挂载到容器组件的实例上(有状态组件也可以叫做容器组件,无状态组件也可以叫做展示组件),然后传递props到展示组件,展示组件接收到props,把props塞到模板里面
24、在哪些生命周期中可以修改组件的state
componentDidMount和componentDidUpdate
constructor、componentWillMount中setState会发生错误:setState只能在mounted或mounting组件中执行
componentWillUpdate中setState会导致死循环
25、调用render时,DOM一定会更新吗,为什么
不一定更新
React组件中存在两类DOM,render函数被调用后, React会根据props或者state重新创建一棵virtual DOM树,虽然每一次调用都重新创建,但因为创建是发生在内存中,所以很快不影响性能。而 virtual dom的更新并不意味着真实DOM的更新,React采用diff算法将virtual DOM和真实DOM进行比较,找出需要更新的最小的部分,这时Real DOM才可能发生修改
所以每次state的更改都会使得render函数被调用,但是页面DOM不一定发生修改
26、展示组件(Presentational component)和容器组件(Container component)之间有何不同
展示组件:展示专门通过props接受数据回调,并且几乎不会有自身的状态
容器组件:展示组件或者其他容器组件提供容器和行为;并调用actions,将其作为回调提供给展示组件,容器组件经常是有状态的
27、setState的两个参数
第一个参数是要改变的state对象
第二个参数是state导致的页面变化完成后的回调,等价于componentDidUpdate
28、React的生命周期函数中,当props改变时 会引发的后续变化,rander()函数什么时候执行
componentWillUpdate(){}之后
render
componentDidupdate(){}之前
29、React 和 Vue 相对于JQ在开发上有哪些优点?
虚拟DOM的优化,组件化利于维护,组件化方便复用
30、react-router的原理
BrowserRouter或hashRouter用来渲染Router所代表的组件
Route用来匹配组件路径并且筛选需要渲染的组件
Switch用来筛选需要渲染的唯一组件
Link直接渲染某个页面组件
Redirect类似于Link,在没有Route匹配成功时触发
31、为什么React Router v4中使用 switch 关键字 ?
虽然
当你想要仅显示要在多个定义的路线中呈现的单个路线时,可以使用 “switch” 关键字,使用时,
与已定义的路由进行匹配。找到第一个匹配项后,它将渲染指定的路径。从而绕过其它路线
32、了解redux么,说一下redux
redux 是一个应用数据流框架,主要是解决了组件间状态共享的问题,原理是集中式管理,主要有三个核心方法,action,store,reducer
三大原则:
1)唯一数据源(整个应用的 state 被储存在一棵 object tree 中,并且这个 object tree 只存在于唯一一个 store 中)
2)reducer必须是纯函数(输入必须对应着唯一的输出)
3)State 是只读的, 想要更改必须经过派发action
redux的工作流程:
使用通过reducer创建出来的Store发起一个Action,reducer会执行相应的更新state的方法,当state更新之后,view会根据state做出相应的变化
1)提供getState()获取到state
2)通过dispatch(action)发起action更新state
3)通过subscribe()注册监听器
33、redux数据流通的过程
1)用户操作视图
2)发起一次dispatch。有异步:返回一个函数(使用thunk中间件),没有异步:return {}
3)进入reducer,通过对应的type去修改state,最后返回一个新的state
34、connect()前两个参数是什么?
mapStateToProps(state, ownProps)
允许我们将store中的数据作为props绑定到组件中,只要store更新了就会调用mapStateToProps方法,mapStateToProps返回的结果必须是object对象,该对象中的值将会更新到组件中
mapDispatchToProps(dispatch, [ownProps])
允许我们将action作为props绑定到组件中,如果不传这个参数redux会把dispatch作为属性注入给组件,可以手动当做store.dispatch使用
mapDispatchToProps希望你返回包含对应action的object对象
35、redux本身有什么不足?
1)向事件池中追加方法时,没有做去重处理
2)把绑定的方从在事件池中移除掉时,用的是arr.splice(index,1),这样可能会引起数组塌陷
3)reducer中state,每次返回都需要深克隆,可以在redux中获取状态信息时,深克隆,这样就不用在reducer里深克隆了
36、你怎么理解redux的state的
数据按照领域(Domain)分类,存储在不同的表中,不同的表中存储的列数据不能重复
表中每一列的数据都依赖于这张表的主键,表中除了主键以外的其他列,互相之间不能有直接依赖关系
把整个应用的状态按照领域(Domain)分成若干子State,子State之间不能保存重复的数据
State以键值对的结构存储数据,以记录的key/ID作为记录的索引,记录中的其他字段都依赖于索引
State中不能保存可以通过已有数据计算而来的数据,即State中的字段不互相依赖
37、React,redux可以运行在服务端吗?有什么优势
1)利于SEO
2)提高首屏渲染速度
3)同构直出,使用同一份JS代码实现,便于开发和维护
38、列出 Redux 的组件
1)Action – 这是一个用来描述发生了什么事情的对象
2)Reducer – 这是一个确定状态将如何变化的地方
3)Store – 整个程序的状态/对象树保存在Store中
4)View – 只显示 Store 提供的数据
39、解释 Reducer 的作用
Reducers 是纯函数,它规定应用程序的状态怎样因响应 ACTION 而改变。Reducers 通过接受先前的状态和 action 来工作,然后它返回一个新的状态。它根据操作的类型确定需要执行哪种更新,然后返回新的值。如果不需要完成任务,它会返回原来的状态
40、Store 在 Redux 中的意义是什么?
Store 是一个 JavaScript 对象,它可以保存程序的状态,并提供一些方法来访问状态、调度操作和注册侦听器。应用程序的整个状态/对象树保存在单一存储中。因此,Redux 非常简单且是可预测的。我们可以将中间件传递到 store 处理数据,并记录改变存储状态的各种操作。所有操作都通过 reducer 返回一个新状态