JS部分
HTML + CSS
React
Vue
ES6
webpack,node.js,Git等
1.Redux遵循的三个原则是什么?
单一数据来源
:整个应用的状态存储在单个 store 中的对象/状态树里。单一状态树可以更容易地跟踪随时间的变化,并调试或检查应用程序。状态是只读的
:改变状态的唯一方法是去触发一个动作。动作是描述变化的普通 JS 对象。就像 state 是数据的最小表示一样,该操作是对数据更改的最小表示。使用纯函数进行更改
:为了指定状态树如何通过操作进行转换,需要用纯函数。纯函数是那些返回值仅取决于其参数值的函数。
2.redux工作流程
首先,UI组件发出 Action。然后,Store 自动调用 Reducer,并且传入两个参数:当前 State 和收到的 Action。 Reducer 会返回新的 State 。State 一旦有变化,Store 就会调用监听函数。用户可以通过store.getState()得到当前状态。
//伪代码,仅供参考
() => store.dispatch({ type: 'CHANGE_VISIBLE' ,payload : text}) //发出Action
//reducer接受并处理数据
const reducer = (state = {
visible : false,
attritube : [],
}, action) => {
switch (action.type) {
case 'CHANGE_VISIBLE':
return { ...state, visible: !state.visible , attritube : action.payload }
default:
return state
}
}
//react类组件通过装饰器获取state数据
@connect(state => ({ visible: state.visible , attritube : state.attritube}), dispatch => ({}))
//函数式组件
export default connect((state => ({visible: state.visible , attritube : state.attritube})))('组价名')
3.React 中 key 的作用是什么?
Keys 是 React 用于追踪哪些列表中元素被修改、被添加或者被移除的辅助标识。
在开发过程中,我们需要保证某个元素的 key 在其同级元素中具有唯一性。在 React Diff 算法中 React 会借助元素的 Key 值来判断该元素是新近创建的还是被移动而来的元素,从而减少不必要的元素重渲染。此外,React 还需要借助 Key 值来判断元素与本地状态的关联关系。
React中key的使用
4.React生命周期
- 常用的React生命周期方法 :
constructor()
: 如果不初始化 state 或不进行方法绑定,则不需要为 React 组件实现构造函数。
构造函数仅用于以下两种情况:1. 通过给 this.state 赋值对象来初始化内部 state。2.为事件处理函数绑定实例
constructor(props) {
super(props);
// 不要在这里调用 this.setState()
this.state = { counter: 0 };
this.handleClick = this.handleClick.bind(this);
}
-
Render()
: render() 方法是 class 组件中唯一必须实现的方法。
render() 函数应该为纯函数,这意味着在不修改组件 state 的情况下,每次调用时都返回相同的结果,并且它不会直接与浏览器交互。 -
componentDidMount()
: 会在组件挂载后(插入 DOM 树中)立即调用。如需通过网络请求获取数据,此处是实例化请求的好地方。可以在 componentDidMount() 里直接调用 setState()。 -
componentDidUpdate()
: componentDidUpdate(prevProps, prevState, snapshot)会在更新后会被立即调用。首次渲染不会执行此方法 -
componentWillUnmount()
: 会在组件卸载及销毁之前直接调用。在此方法中执行必要的清理操作,例如,清除 timer,取消网络请求或清除在 componentDidMount() 中创建的订阅等。componentWillUnmount() 中不应调用 setState(),因为该组件将永远不会重新渲染。组件实例卸载后,将永远不会再挂载它。
5.vue react 怎么检测数据变化的
React
- 16年之前可以使用componentWillReveiveProps来监听props的变换。16年之后在最新版本的React中可以使用新出的getDerivedStateFromProps进行props的监听,getDerivedStateFromProps可以返回null或者一个对象,如果是对象,则会更新state
- getDerivedStateFromProps的触发条件 : 只要调用setState就会触发getDerivedStateFromProps,并且props的值相同,也会触发getDerivedStateFromProps(16.3版本之后)
- 状态变化只能通过setState,调用setState就会更新状态重新渲染dom
Vue
- vue监听变量变化依靠的是watch
6.React中怎么让setState同步更新?
- 回调 : setState函数的第二个参数允许传入回调函数,在状态更新完毕后进行调用,例如下面的这个例子
this.setState({
data: '666'
}, () => {
console.log('加载完成')
});
- promise : 利用promise的特性,可以使用promise封装一个函数去一劳永逸的解决这个问题
setStateAsync(state) {
return new Promise((resolve) => {
this.setState(state, resolve)
});
}
- async+await : 相当于promise的优雅版,我们可以利用await"等一等"的特性去让程序等待await后面的函数做完以后再执行下面的代码(当然,await必须要配合async使用),例如下面的小例子
async myfun(){
await this.setState({
data: '666'
});
}
7.什么是immutable, 为什么要使用它
-
Immutable Data 就是一旦创建,就不能再被更改的数据。对 Immutable 对象的任何修改或添加删除操作都会返回一个新的 Immutable 对象
-
Immutable 实现的原理是 Persistent Data Structure (持久化数据结构),也就是使用旧数据创建新数据时,要保证旧数据同时可用且不变
TIP:当然,通过这一点,我们可以去做时间旅行,也就是以前调用之前存在过的旧数据。 -
同时为了避免 deepCopy 把所有节点都复制一遍带来的性能损耗, Immutable 使用了 Structural Sharing···· (结构共享),即如果对象树中一个节点发生变化,只修改这个节点和受它影响的父节点,其它节点则进行共享。
A
/ \
A B
/ \ / \
C D E F
//例如我们现在数据F发生改变,那么他只会影响到B与A,其他不会受到影响的数据直接复制过来就好了无需重新进行操作,性能有所提升。
8. 什么是 JSX
JSX是javascript的语法扩展。它就像一个拥有javascript全部功能的模板语言 在里面可以使用js代码
它实现的原理就是react封装了createElement(第一个参数是 标签名,第二个参数是对象 包含了所有的属性,第三个是子节点)。
9. React的diff算法
React Diff 算法的差异查找实质是对两个JavaScript对象(虚拟DOM和真实DOM)的差异查找,所以React更新阶段才会有Diff算法的运用。
更多
10.React中间件(React-thunk , React-promise)
在React种有三个部分 :
(1)Reducer:纯函数,只承担计算 State 的功能,不合适承担其他功能,也承担不了,因为理论上,纯函数不能进行读写操作。
(2)View:与 State 一一对应,可以看作 State 的视觉层,也不合适承担其他功能。
(3)Action:存放数据的对象,即消息的载体,只能被别人操作,自己不能进行任何操作。
而想要在React种异步请求数据,在Action中请求无疑是最完美的。即store.dispatch()方法,可以添加请求数据功能。而中间件就是一个函数,对store.dispatch方法进行了改造,在发出 Action 和执行 Reducer 这两步之间,添加了其他功能。
redux-thunk
中间件,改造了store.dispatch,使得后者可以接受函数作为参数。与之相对应的redux-promise
返回一个 Promise 对象。
React-thunk的使用
11.装饰器语法
- 什么是装饰器?
Decorator 是 ES7 的一个新语法,他可以对一些对象进行装饰包装然后返回一个被包装过的对象,
可以装饰的对象包括:类,属性,方法等。
- 装饰器的作用
装饰器的作用就是为已经存在的函数或对象添加额外的功能。 装饰器应用场景及理解:
装饰器本质上是一个函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能 。
这里主要介绍一下类装饰器,使用类装饰器可以减少一些代码的重复编写。
此时装饰器看起来更像是一个父类,但它又不是一个父类,因为被装饰的类重写一些生命周期函数的时候
装饰器里面的生命周期函数并不会被覆盖执行。对于componentDidMount 来说,先执被装饰类的
componentDidMount 再执行 装饰器内的componentDidMount;对于componentWillUnmount 来讲
先执行装饰器的componentWillUnmount 再执行被装饰的类的componentWillUnmount
装饰器connect实例
关于装饰器的安装及引用在这里并不做赘述,只介绍如何在React中使用装饰器
@connect(state => ({ banner: state.banner}), dispatch => ({
getBanner() {
dispatch(getBannerAction)
},
}))
class PicturesWall extends React.Component {
componentDidMount() {
this.props.getBanner()
}
//使用 banner 变量
}
在这个类组件中,调用 componentDidMount 生命周期钩子,触发了connect 中的 getBanner 函数,并获取了 redux 中的 banner 变量。在这里 装饰器connect 包裹了 PicturesWall 组件 并触发一个异步函数,将store中的 banner变量传给组件
//函数式组件,换了种写法,作用都一样
const commodityclass = () => {
...
}
export default connect((state => ({ model_payload: state.model_payload})))(commodityclass)
12.React state 和 props 有什么不同
props 是一个从外部传进组件的参数,主要作为就是从父组件向子组件传递数据,它具有可读性和不变性,只能通过外部组件主动传入新的 props 来重新渲染子组件,否则子组件的 props 以及展现形式不会改变。
state 是组件自身的状态,的主要作用是用于组件保存、控制以及修改自己的状态的一些数据,它只能在 constructor 中初始化,它算是组件的私有属性,不可通过外部访问和修改,只能通过组件内部的 this.setState 来修改,修改 state 属性会导致组件的重新渲染。
- state 是组件自己管理数据,控制自己的状态,可变;
- props 是外部传入的数据参数,不可变;
13.React 的路由懒加载怎么实现?
-
使用传统的 import 的方式。可以在函数内 return 一个 import, 添加 webpackChunkName 的注释,这样 webpack 打包时就会将对应的文件单独打包,当函数执行时再去加载这个包。
return import( /* webpackChunkName: "lodash" */ 'lodash').then(_ => {}
-
使用 React.lazy 实现。导入时调用 React.lazy 并给他一个函数参数,函数中返回 import React.lazy(() => import("./XXX"))。配合 Suspense 可以实现在模块未加载完成的时候给用户一个提示。
14.类组件和函数组件有什么区别
类组件可以使用其他特性,如状态 state 和生命周期钩子。
当组件只是接收 props 渲染到页面时,就是无状态组件,就属于函数组件
函数组件的性能比类组件的性能要高, 因为类组件使用的时候要实例化,而函数组件直接执行函数取返回结果即可。为了提高性能,尽量使用函数组件。
函数组件没有this,没有生命周期,没有状态state,
类组件有this,有生命周期,有状态state。
15.什么是高阶组件、受控组件、非受控组件?
高阶组件
是个函数,输出结果是个新组件,可以对输入的组件进行加工,并返回一个具有特定功能的组件。
受控组件
相当于input中的value值通过state值获取,onChange事件改变state中的value值。实现了双向绑定,任意一方的数据发生变化,另一方也会随之改变 。
非受控组件
不需要设置对应的state属性,可通过ref来直接操作真实的dom。
16.vuex和redux的区别
表面区别就是vuex是通过将store注入到组件实例中,通过dispatch和commit来维护state的状态,并可以通过mapstate和this.$store来读取state数据。而redux则是需要通过connect将state和dispatch连接来映射state并操作state。redux没有commit,直接通过dispatch派发一个action来维护state的数据。并且只能通过reducer一个函数来操作state。
rudex使用的是不可变数据;vuex是可变的数据。
rudex每次都是返回一个新的state;而vuex是直接改变state。
17.为什么使用React,React 有那些优势?
- React 速度很快:它并不直接对DOM进行操作,而是引入一个叫做虚拟DOM的概念,安插在JavaScript逻辑和实际的DOM之间,所以性能比较好
- 跨浏览器兼容:虚拟DOM帮助我们解决了跨浏览器问题,它为我们提供了标准化的API,甚至可以在IE8中使用
- 一切都是component:代码更加模块化,重用代码更容易,代码可维护性更高
- 单向数据流:Flux 是一个用于在 JavaScript 应用中创建单向数据层的架构,它随着React视图库的开发而被Facebook概念化
- 同构、纯粹的JavaScript:因为搜索引擎的爬虫程序依赖的是服务端响应,而不是JavaScript的执行,所以预渲染应用有助于搜索引擎的优化
- 兼容性好:比如使用RequireJS来加载和打包,而Browserify和Webpack适用于构建大型应用。他们使得那些艰难的任务变得简单化。
18.为什么有时连续多次setState只有一次生效?
原因就是 React会将存储的多个 setState进行合并 ,如果你想立即使用上次 setState后的结果进行下一次 setState,可以让 setState 接收一个函数而不是一个对象。这个函数用上一个 state 作为第一个参数,将此次更新被应用时的 props 做为第二个参数。
19.redux中sages和thunk中间件的区别,优缺点
redux-thunk
和redux-saga
都是redux的中间件,都是用来处理异步请求的。中间件是指在action
与store
之间实现某种功能的函数
使用redux-thunk处理异步等副作用操作,在action中处理异步等副作用操作,此时的action是一个函数,以dispatch,getState作为形参,函数体内的部分可以执行异步。通过redux-thunk来处理异步,action可谓是多种多样,不利于维护。
在redux-saga中,action是plain object(原始对象)
,并且集中处理了所有的异步操作。使用saga,我们生成一个集中处理异步的saga.js文件,
saga优点:
(1)集中处理了所有的异步操作,异步接口部分一目了然
(2)action是普通对象,这跟redux同步的action一模一样
(3)通过Effect,方便异步接口的测试
(4)通过worker 和watcher可以实现非阻塞异步调用,并且同时可以实 现非阻塞调用下的事件监听
(5) 异步操作的流程是可以控制的,可以随时取消相应的异步操作。 redux-saga使用了ES6中的Generator功能,避免了像redux-thunk的回调地狱。
缺点:太复杂,学习成本较高
20.为什么说react是view(视图层)?
• React本身就并不非常认可MVC开发模式
• React被认为是视图层的框架是因为它整个结构就是基于组件的,一切都是组件,然后组件就是渲染页面的基础。
• 不论组件中包含的jsx,methods,state,props,都是属于组件内部的。所以从这个角度看的话,react就是视图层框架。
21.说一下对 纯函数 的理解。
定义:一个函数的返回结果只依赖于它的参数,并且在执行的过程中没有副作用,我们就把该函数称作纯函数。
纯函数的特点 :
- 函数的返回结果只依赖于它的参数。
- 函数执行过程里面没有副作用。即 函数执行不会对外部变量产生影响
- 没有额外的状态依赖。( 指方法内的状态都只在方法的生命周期内存活,这意味着不能在方法内使用共享变量,因为会带来不可知因素。)
纯函数的优点 : 纯函数非常“靠谱”,执行一个纯函数你不用担心它会干什么坏事,它不会产生不可预料的行为,也不会对外部产生影响。不管何时何地,你给它什么它就会乖乖地吐出什么。如果你的应用程序大多数函数都是由纯函数组成,那么你的程序测试、调试起来会非常方便。
22.React性能优化
23.调用 setState 之后发生了什么?
在代码中调用 setState 函数之后,React 会将传入的参数对象与组件当前的状态合并,然后触发所谓的调和过程(Reconciliation)。经过调和
过程,React 会以相对高效的方式根据新的状态构建 React 元素树并且着手重新渲染整个 UI 界面。在React 得到元素树之后,React 会自动计算出新的树与老树的节点差异,然后根据差异对界面进行最小化重渲染。在Diff算法中,React 能够相对精确地知道哪些位置发生了改变以及应该如何改变,这就保证了按需更新,而不是全部重新渲染。
24.react中的JSX原理
用 JavaScript 对象来表现一个 DOM 元素的结构JavaScript 写起来太长了,结构看起来又不清晰,用 HTML 的方式写起来就方便很多了。
于是 React.js 就把 JavaScript 的语法扩展了一下,让 JavaScript 语言能够支持这种直接在 JavaScript 代码里面编写类似 HTML 标签结构的语法,这样写起来就方便很多了。编译的过程会把类似 HTML 的 JSX 结构转换成 JavaScript 的对象结构。
React.createElement 会构建一个 JavaScript 对象来描述你 HTML 结构的信息,包括标签名、属性、还有子元素等。
jsx实际上就是一种javascript对象,他经过react语法的构造,还有编译转化,最后得到dom元素,可以插到页面中:所谓的 JSX 其实就是 JavaScript 对象,所以使用 React 和 JSX 的时候一定要经过编译的过程:
JSX —使用react构造组件,bable进行编译—> JavaScript对象 — ReactDOM.render()—>DOM元素 —>插入页面
25.createElement 和 cloneElement 有什么区别?
React.createElement():JSX 语法就是用 React.createElement()来构建 React 元素的。它接受三个参数,第一个参数可以是一个标签名。如 div、span,或者 React 组件。第二个参数为传入的属性。第三个以及之后的参数,皆作为组件的子组件。
React.cloneElement()与 React.createElement()相似,不同的是它传入的第一个参数是一个 React 元素,而不是标签名或组件。新添加的属性会并入原有的属性,传入到返回的新元素中,而旧的子元素将被替换,旧元素的key和ref会保留。