DVA整合reducer,initialState、action、saga

app.model({namespace: 'products',state: {list: [],loading: false,},在dom ready之后运行subscriptions: [function(dispatch) {dispatch({type: 'products/query'});},],effects: {['products/query']: function*() {yield call(delay(800));yield put({type: 'products/query/success',payload: ['ant-tool', 'roof'],});},},reducers: {['products/query'](state) {return { ...state, loading: true, };},['products/query/success'](state, { payload }) {return { ...state, loading: false, list: payload };},},
});

介绍下这些 model 的 key :(假设你已经熟悉了 redux, redux-saga 这一套应用架构)

  • namespace - 对应 reducer 在 combine 到 rootReducer 时的 key 值
  • state - 对应 reducer 的 initialState
  • subscription - elm@0.17 的新概念,在 dom ready 后执行,这里不展开解释,详见:A Farewell to FRP
  • effects - 对应 saga,并简化了使用
  • reducers

虚拟DOM

使用普通js来描述DOM结构

在react、vue等技术出现之前,我们要改变页面内容只能通过遍历查询dom树的方式找到要修改的dom然后修改样式或结构来达到更新dom的目的,这种方式非常消耗资源(操作dom会引起浏览器的回流和重绘)。但是如果建立一个与dom树相应的虚拟dom对象(js对象),对象嵌套的方式表示dom树及其层级结构,这样对dom的更改就变成了对js对象的操作,性能开销也变小。

Vue和React的区别

  • vue提供一些便捷的指令和属性

  • React使用JSX模板,允许HTML和js混写,Vue基于html的模板语法

  • 在响应式方面,Vue的数据改动时,界面会自动更新,React需要调动setState方法。

    ​ 把两者称为Push-basedPull-based。所谓Push-based就是说,改动数据之后,数据本身会把这个改动推送出去,告知渲染系统自动进行渲染。在React里面,它是一个Pull的形式,用户要给系统一个明确的信号说明现在需要重新渲染了,这个系统才会重新渲染

React

React响应式原理

  • 开发者只需要关注数据,当状态改变时,React框架会自动根据新的状态重新渲染构建UI。
  • React框架在接受到状态改变时,会根据当前渲染树,结合最新的状态改变通过Diff算法计算出树中改变的部分,只更新变化的部分,从而避免整棵树重构,提高性能。状态改变后React不会立即去计算并渲染DOM树变化的部分,react会在DOM的基础上建立一个抽象层,即虚拟DOM树,对数据和状态的任何变化都会自动且高效的同步到虚拟DOM,最后在批量同步到真实DOM上,而不是每次改变都去操作DOM。

React中的setState

​ React中的state不能直接修改,需要调用setState()的方法来修改。

​ setState执行的时候可以简单认为属于原生js执行的空间,那么属于同步,而被react处理过的空间属于异步空间,但是如果多次使用setState修改state,react为了提高性能会按批次更新state然后render即异步操作,所以setState()后立即取state中的值并不是更新之后的状态,如果想要取得更新之后的state可以在setState()的第二个参数callback中取得新值。setState()有两个参数,第一个参数可以是Object或者函数,当参数是Object时,对应的key,value就是更新后的值,如果参数是函数,setState()会将上一次更新的结果作为参数传入这个函数中。

React组件通信的方式

  • 父组件向子组件传递props
  • 父组件将一个回调函数传入子组件,子组件调用该函数可以向父组件通信
  • 使用context可以避免组件嵌套传参,provider生产者产生数据,consumer消费者在各个组件中传递参数
  • 利用组件共同的父组件通信
  • redux,dva,mobx 在view中触发action,改变state,进而改变其他组件的view
  • 引用ref可以获得子组件的实例
  • Render Props 渲染的细节由父组件控制

Redux和Vuex的区别

  • Vuex改进了Redux中的action和reducer函数,用mutations变化函数取代reducer,无需switch,只需要在对应的mutation函数改变state值就可以。
  • Vuex由于Vue的自动重新渲染特性,不需要重新订阅渲染函数render,只要生成新的state就可以。
  • Vuex数据流的顺序是View调用store.commit提交对应的请求到Store中对应的mutation函数 ,让store改变state(vue检测到数据变化自动渲染)

redux-saga中遇到的坑

​ saga是一个系列的工作文件,拦截action执行,执行异步操作,put出一个新的action改变reducer

  • saga不会强迫我们捕获异常
  • generator调试环境糟糕,babel的source-map会错位
  • action定义谨慎,避免action在saga和reducer之间重复触发

Hooks和redux

Hooks

​ Hooks是在react16.8版本中出现的一个新功能,是一种函数,它可以实现组件的逻辑复用,可以让我们在函数组件中使用类组件中的状态和生命周期等功能,hook都是以use开头

  1. useState 创建状态 返回数组,第一个参数是状态,第二个是改变状态的函数
  2. useEffect 副作用函数(数据获取,页面渲染结束后执行的操作)第一个参数是执行的操作,第二个参数是依赖列表,如果没有第二个参数,则会在第一个渲染结束和每次更新渲染页面的时候都会执行该函数
  3. useRef 创建ref ,此索引在整个生命周期都不会变,可以获取组件或者元素的实例,可以做输入框聚焦和动画
  4. useMemo 可以做函数组件优化,只有当依赖改变时才会触发,和usCallback作用类似
  5. useCallback 类似useMemo
  6. useContext 获取上下文注入值 可以结构出provider和consumer两个方法 provider生产者传递数据,consumer消费者可以获取数据
  7. useLayoutEffect 和useEffect类似,在DOM更新之后执行,执行顺序早于useEfffect,DOM更新完以后才会渲染。

redux

redux是一个可预测的状态容器,实质是单向数据流的思想。

redux三大特性:单一数据流、状态state是只读的、状态修改事由纯函数完成

redux由action、reducer、store组成

  • action是view发出的通知state发生变化的动作
  • reducer 接收action和当前的state作为参数,是改变state的具体计算过程
  • store 是保存数据的地方。 redux提供createStore这个函数来生成store
    • store.getState 获取当前时刻的state
    • store.dispatch view派发 action的方法
    • store.subscribe 设置监听函数 可以监听state,当state改变时可以做相应的操作。

Fiber

​ Fiber是React16中新的协调引擎,主要目的是使虚拟DOM进行增量式渲染,可以类比generator函数。fiber可以认为是最小的工作单元,提升对于动画,布局,手势等场景的适用性,核心功能:增量渲染,将渲染工作分解为多个区块并将其散落到每一帧中。

  • 暂停工作,并回来
  • 为不同类型任务分配等级
  • 重用以前完成的工作
  • 不需要的时候终止任务

为什么不建议在componentWillMount做Ajax操作?

在React16之后将会废弃这个钩子,虽然可以使用,但是会有警告,而且会增加渲染的时间出现白屏现象。在React16之后采用了Fiber架构,只有componentDidMount钩子是确定执行一次的,componentWillMount钩子有可能会执行多次。在render阶段,可能会被暂停,中止或重启。

React的diff算法规则是什么

diff算法即差异查找算法,对于HTML DOM结构就是tree的差异查找算法,只有在更新阶段才会有diff算法的应用,react为了降低时间复杂度是按照层比较新旧两个虚拟dom树。

  1. tree diff 新旧两颗dom树,逐层对比的过程就是tree diff,当整颗dom树逐层对比完成后,那必然会找到需要更新的元素

  2. component diff 在进行tree diff 的时候每一层都有自己的组件,组件级别的对比就是component diff ,如果对比前后组件的类型不同,则需要移除旧组件创建新的组件渲染到页面。react只会匹配类型相同的组件,如果A组件被B替换,react会直接删除A然后创建B组件;如果A组件转移到同层B组件上,那么A会 被销毁,在B组件下重新生成,以A为根节点的树整个都被重建,虽然会浪费性能,但实际上很少跨层移动dom节点,一般都是同层横向移动。

  3. element diff 在进行组件对比时,如果两个组件类型相同,需要进行元素级别的对比,叫做element diff

    对于列表渲染,react在创建时需要为每一项输入一个独一无二的key,方便进行diff运算,在比较新旧子元素的时候是通过key值来精确判断两个节点是否是同一个,如果没有key见谁就更新谁,消耗性能

styled-component的使用

首先引入styled  import styled from  ‘styled-compont’在文件中通过 const  name=styled.div`样式
`
styled.dom标签名
例:
const Title = styled.h1`font-size: 1.5em;text-align: center;color: palevioletred;
`;
render(<Title>Hello styled-component</Title>
);

React状态管理工具都有哪些,Redux actionCreator都有什么?

mobx、react等

Redux actionCreator用来创建action,通常只用来返回action对象

Vue和React中Diff算法的区别

都是忽略跨级比较,只做同级比较。vue diff时调动patch函数,参数是vnode和oldVnode,分别代表新旧节点。

  • vue对比节点,当节点元素相同但是classname不同时就会被认为是不同类型的元素,会删除重建,react认为是同类型节点只是修改属性。
  • vue的列表对比,采用的是两端到中间的对比方式,而react采用的是从左到右依次对比的方式。当一个集合只是把最后一个节点移动到第一个,react会把前面的节点依次移动,vue只会把最后一个节点移到第一个。总体上说vue更加高效。

为什么有时连续setState只有一次生效

如果连续setState同一个值,批量更新策略会对其进行覆盖,取最后一次执行,如果同时setState多个不同的值,在更新时会对其进行合并批量更新。如果想对上次setState后的结果进行下一次setState,可以让setState接收一个函数,这个函数用上一个state作为第一个参数,这次被更新的props作为第二个参数

React JSX组件渲染过程

  • 使用JSX编写的组件后所有JSX代码通过babel转化为React.createELement执行
  • createElement函数对key和ref等特殊的props进行处理,并获取defaultProps对默认props进行赋值,对传入的子节点进行处理,最终构成一个ReactElement对象,即所谓的虚拟DOM
  • ReactDOM.render将生成好的虚拟DOM渲染到指定的容器上,采用了批处理、事务等机制并对特定浏览器进行性能优化最终转换为真实DOM

Redux中间件原理?异步中间件thunk和saga如何使用

redux添加中间件 applyMiddleware

redux中间件的执行时机在action发出和reducer执行之间,中间件的实质就是对redux中store.dispatch函数的再封装。(要保持reducer的纯净)

thunk

import {createStore, applyMiddleware} from 'redux'
import thunk from 'redux-thunk'
import rootReducer from './reducers'export default createStore(rootReducer,applyMiddleware(thunk)
)

redux-thunk是把异步操作放在action里面,而saga是把异步逻辑拆分出来放在一个异步文件里面。

thunk检查action的类型,如果是函数就执行这个action,并把dispatch、getState, extraArgument 作为参数传递进去,否则就调用 next 让下一个中间件继续处理 action。

saga

redux-saga比redux-thunk更加强大,不止可以充当中间件的作用,可以实现多种代码效果

import $http from '@/utils/http'
import { put,takeEvery,call } from 'redux-saga/effects'
import {LOADLIST,GETLIST,LOADSHOES,GETSHOES,LOADCLOTHES,GETCLOTHES} from './actionType'//saga中间件中做axios请求
function* foo(){let recommend=yield call($http.get,{url:'recommend.json'})let shoes=yield call($http.get,{url:'shoes.json'})let clothes=yield call($http.get,{url:'clothes.json'})yield put({type:LOADLIST,list:recommend.data.data.hotList})yield put({type:LOADSHOES,shoes:shoes.data.data.list})yield put({type:LOADCLOTHES,clothes:clothes.data.data.list})// console.log(shoes);
}function* saga(){yield takeEvery(GETLIST,foo)yield takeEvery(GETSHOES,foo)// yield takeEvery(GETCLOTHES,foo)
}
export default saga
import { createStore, applyMiddleware } from 'redux'
import createSagaMiddleware from 'redux-saga'
import { helloSaga } from './sagas'
import reducer from 'xxxx'const sagaMiddleware = createSagaMiddleware()const store = createStore(reducer,   // 这个reducer是用combineReducers综合导出的reducerapplyMiddleware(sagaMiddleware)    // 声明使用saga中间件
)sagaMiddleware.run(helloSaga)

异步调用

  • sagas被实现为Genetator函数,他会yield对象到 redux-saga middleware
  • yield的对象都是一类指令,可被middleware解释执行
  • 当middleware取得一个yield后的Promise,middleware会暂停saga,直到该promise完成
  • 一旦promise被reslove,middleware会恢复saga执行,直到遇到下一个yield

takeEvery可以执行多个saga

put 使用功能和dispatch一样,一般只在saga函数内部使用。

call和fork

这两个函数主要都是用来发起异步操作的(如发送请求),不同的是 call 发起的是阻塞操作,即必须等待该异步操作完全完成才能进行后续的操作,而 fork 是非阻塞的,因此可以使用 fork 来实现多个并发的请求操作(fork相当于生成了一个task——一个在后台运行的进程)

call(fn, …args):第一个参数是一个generator函数(也可以是一个返回Promise或任意其它值的普通函数),后面的参数都是依次传入这个函数的形参数值,返回值是promise的resolve结果

call默认是接收到promise成功标志时解除阻塞,但是如果是普通函数的话,可能达不到阻塞的效果。

React加载组件的方式

子组件、children、render函数

为什么使用自定义hooks

hooks都是use开头的函数,可以把公用的逻辑封装起来复用,缩减嵌套,实现代码拆分

设置父组件传值的类型

可以使用props-types这个插件

传值校验
子组件名.propTypes= {avname= PropTypes.number.isRequiredcontent:PropTypes.string,index:PRopTypes.number
}
设置默认值
子组件名.defaultProps = {avname:'松岛枫’
}

React顶层DOM对象

  • React.Children 组件中的节点
  • React.cloneElement type(ReactElement),[props(object)],[children(ReactElement)] 克隆并返回一个新的ReactElement(内部子元素也会跟着克隆),新返回的元素会保留有旧元素的props,ref,key,也会集成新的props(只要在第二个参数中有定义)
  • React.createElement…

根据原来的组件生成新的组件,添加属性

  • HOC高阶组件
  • 顶层API React.cloneEmelent

Mobx和redux的区别

Mobx

创建store,对store中的数据进行监听

 constructor(title) {makeObservable(this, {finished: observable,title: observable,changeFinished: action})this.title = title}

mobx是面向对象编程的状态管理库,在action中定义改变状态的函数,在store中集中管理state和action。mobx状态可变,可以直接修改。mobx没有一个全局状态树,状态分散在各个独立的store中。

mobx流程:view中触发action,在action中修改state,通过computed拿到state的计算值,自动触发对应的reactions,这里包含autorun,渲染视图等。

原理:使用Object.defineProperty拦截数据的访问,一旦值发生变化,将会调用react的render方法重新渲染视图或者触发autorun。

autorun

当autorun函数中依赖的可观察属性发生改变时,就会自动触发autorun函数的执行,可以执行一些副作用操作。它不同于computed,不会产生一个新值,可以用来打印日志等。

observable

observable装饰器可以装饰一个属性,当这个属性发生改变时就会触发相应的动作,这个属性的类型可以包括string、boolean、array、object等

oberver

当可观察属性改变时,调用render方法重新渲染视图

makeObservable

手动为store中的属性添加类型,有两个参数,第一个是当前环境的this,第二个参数是对象,在这个对象中为属性添加响应式或者指定action和computed,

key为属性,value是要指定的类型。

 makeObservable(this, {finished: observable,title: observable,changeFinished: action})

makeAutoObservable

自动为store中的属性指定observable和action等

一个参数就是当前环境的this

 constructor(todos) {makeAutoObservable(this)this.todos = todos}

Redux和mobx的区别

  • redux将数据保存在单一的store中,mobx的数据分散在多个store中
  • redux使用 plainobject保存数据,需要手动出炉变化后的操作,mobxobservable保存数据,并且数据变化后自动处理响应操作
  • redux状态不可变,不能直接修改状态,应该返回一个新的状态,使用纯函数;mobx状态可变,也可以直接修改
  • mobx面向对象的编程,redux面向函数式编程。

为什么redux的reducer为什么要设计成不能直接修改原状态,而返回修新状态对象

  • 源码上来说redux会对reducer返回的状态进行引用地址的比较,不同才更新,直接修改源码不会更新
  • 设计角度,要知道redux返回的状态是否有改变,必须对状态对象进行深度比较,但是这样比较消耗性能,所以仅进行状态对象引用地址的比较,有开发者决定是否更新,返回新状态才更新。

React优化

  • 使用纯组件
  • 使用React.memo进行组件记忆(高阶组件)对于相同的输入不重复执行
  • 在类组件中可以使用shouldComponentUpdate生命周期函数,决定是否重新渲染组件,使用immutable对象
  • 不使用内联函数和内联样式属性,内联函数会在每次重新渲染时创建一个新的函数
  • 列表函数添加key值
  • 函数组件中可以使用useCallback和useMemo进行组件优化,依赖不改变不重复执行

React的事件代理

React 基于 Virtual DOM 实现了一个 SyntheticEvent (合成事件)层,我们所定义的事件处理器会接收到一个 SyntheticEvent 对象的实例,它完全符合 W3C 标准,不会存在任何 IE 标准的兼容性问题。并且与原生的浏览器事件一样拥有同样的接口,同样支持事件的冒泡机制,我们可以使用 stopPropagation() 和 preventDefault() 来中断它。

react-router里的标签和标签有什么区别

link的跳转行为只会触发相匹配的页面内容更新,而不会刷新整个页面,他做了三件事情:

  1. 有onclick就执行onclick
  2. click的时候阻止a标签默认事件
  3. 根据href(就是to),用history跳转,只是连接改变,但是没有刷新页面。

a标签就是普通的超链接,用于从当前页面挑战到href指向的另一个页面

a标签默认事件禁止后做什么猜实现跳转

DOM操作获取所有的a标签,循环列表为每一个a添加click事件

let domArr=document.getElementsByTagName(‘a’)
[…domArr].forEach(item=>{item.addEventListener(‘click’,function(){location.href=this.href;
})
})

使用import时,webpack对node_modules里的依赖会做什么

  • import只是一个引用,在没有用到的时候不会执行
  • 需要执行的时候去模块里面取值,webpack根据引入方式去判断模块的类型,进行相关转译,babel会默认把ES6的模块转译为CommonJS规范,然后把node_modues里面的依赖打包成自执行函数,模块会传到数组里面,函数运作之后将模块通过module.exports导出

Vue

Object.defineProperty、Proxy

​ vue2使用Object.defineProperty里面的setter和getter方法的观察者模式来实现响应式,但是Object.Property存在以下几种缺陷

  • 无法检测到对象属性的新增或删除

  • 无法检测数组的变化,只能通过重新构造数组的部分方法来实现响应式(push、pop、shift、splice、sort、reverse)

    vue3使用Proxy来代替Object.defineProperty实现了数据响应,Proxy的优势如下:

  • Proxy可以直接监听对象而不是属性,可以直接监听数组的变化

  • Proxy有多大13种拦截方法,不限于apply、ownKyes、deleteProperty、has等,这些是Object.defineProperty不具有的。

  • Proxy返回的是一个新对象,我们可以只操作新对象达到目的,而Object.defineProperty只能遍历对象的属性直接修改属性

    但是Proxy存在浏览器兼容的问题并且无法使用垫片(polyfill)弥补

Vue响应式数据原理

​ vue的响应式主要利用了Object.defineProperty中的getter和setter方法的观察者模式来实现,在组件初始化时会给每一个data属性注册getter和setter,然后new一个自己的watcher对象,这时watcher会立即调用组件的render函数去生成虚拟DOM。调用render时就会用到data属性值,此时会触发getter函数,将当前的watcher函数注册进sub。当data属性值改变时会遍历sub里面的所有watcher对象,通知他们去重新渲染组件。

computed和watch区别

computed

  • 支持缓存,只有当依赖数据发生改变才会重新计算
  • 不支持异步,有异步操作时操作无效,无法监听数据变化
  • 如果一个属性是由其他属性计算而来的,这属性依赖其他属性,是一个一对多或者一对一,一般用computed
  • 如果computed属性值是函数,默认会走get方法,函数返回值就是属性的属性值;在computed中属性都有一个get和set方法,当数据变化时调用set方法。

watch

  • 不支持缓存,数据变化直接触发相应的操作

  • 支持异步函数

  • 监听的函数接收两个参数,第一个是最新的值,第二个是输入之前的值

  • 监听数据必须是data中声明过或者是父组件传递过来的props中的数据,watch有两个参数

    ​ immediate:

    ​ 这样使用watch时有一个特点,就是当值第一次绑定的时候,不会执行监听函数,只有值发生改变才会执行。如果我们需要在最初绑定值的时候也执行函数,则就需要用到immediate属性。

    比如当父组件向子组件动态传值时,子组件props首次获取到父组件传来的默认值时,也需要执行函数,此时就需要将immediate设为true

    
    new Vue({el: '#root',data: {cityName: ''},watch: {cityName: {handler(newName, oldName) {// ...      },immediate: true}} 

    deep

    ​ 当需要监听一个对象的改变时,普通的watch方法无法监听到对象内部属性的改变,只有data中的数据才能够监听到变化,此时就需要deep属性对对象进行深度监听。

    ​ 数组(一维、多维)的变化不需要通过深度监听,对象数组中对象的属性变化则需要deep深度监听。

    
    new Vue({el: '#root',data: {cityName: {id: 1, name: 'shanghai'}},watch: {cityName: {handler(newName, oldName) {      // ...    },deep: true,immediate: true}} 

    设置deep: true 则可以监听到cityName.name的变化,此时会给cityName的所有属性都加上这个监听器,当对象属性较多时,每个属性值的变化都会执行handler。如果只需要监听对象中的一个属性值,则可以做以下优化:使用字符串的形式监听对象属性:

    
    watch: {'cityName.name': {handler(newName, oldName) { // ...    },deep: true,immediate: true}

    watch工作原理

    watch在一开始初始化时,会读取一遍监听的数据的值,这个数据会被收集到watch的watcher,然后给watch设置的handler会被放进watcher的更新函数中,当数据改变时,通知watch的watcher进行更新,设置的handler就会被调用进行更新操作。

Vue组件间通信

  • 父组件向子组件传值通过props

  • 子组件向父组件传值 通过事件的形式 $emit

    ​ 子组件

    changeTitle() {this.$emit("titleChanged","子向父组件传值");//自定义事件  传递值“子向父组件传值”}
    

    父组件

    <app-header v-on:titleChanged="updateTitle" ></app-header>//与子组件titleChanged自定义事件保持一致// updateTitle($event)接受传递过来的文字methods:{updateTitle(e){   //声明这个函数this.title = e;}},
    
  • 中央总线(bus总线)$emit / $on 通过一个空的vue实例作为中央事件总线,用它触发事件和监听事件,可以实现任何组件间通信。

    <div id="itany"><my-a></my-a><my-b></my-b><my-c></my-c>
    </div>
    <template id="a"><div><h3>A组件:{{name}}</h3><button @click="send">将数据发送给C组件</button></div>
    </template>
    <template id="b"><div><h3>B组件:{{age}}</h3><button @click="send">将数组发送给C组件</button></div>
    </template>
    <template id="c"><div><h3>C组件:{{name}},{{age}}</h3></div>
    </template>
    <script>
    var Event = new Vue();//定义一个空的Vue实例
    var A = {template: '#a',data() {return {name: 'tom'}},methods: {send() {Event.$emit('data-a', this.name);}}
    }
    var B = {template: '#b',data() {return {age: 20}},methods: {send() {Event.$emit('data-b', this.age);}}
    }
    var C = {template: '#c',data() {return {name: '',age: ""}},mounted() {//在模板编译完成后执行Event.$on('data-a',name => {this.name = name;//箭头函数内部不会产生新的this,这边如果不用=>,this指代Event})Event.$on('data-b',age => {this.age = age;})}
    }
    var vm = new Vue({el: '#itany',components: {'my-a': A,'my-b': B,'my-c': C}
    });
    </script>
    

  • vuex

  • $attr $listeners 组件间嵌套传递参数

  • provide inject

  • $parent $children 访问父/子实例

  • ref 获取组件实例

Vue-router原理

通过改变url在不重新请求页面的情况下,更新视图。有两种方式实现

  1. Hash 通过hashChange监听url的变化,每次改变hash都会在浏览器访问历史中增加一个记录

  2. History H5新增的方法 pushState与replaceState 可以将url替换并且不刷新页面

    ​ pushState将新路由添加到浏览器访问历史的栈顶

    ​ replaceState 将新路由添加到浏览器访问历史的栈顶,而是替换掉当前的路由

Vue组件懒加载

  • 异步组件实现路由懒加载
    component: resolve=>(require(["@/components/HelloWorld"],resolve))
    
  • es提出的import(推荐)
    const HelloWorld = ()=>import("@/components/HelloWorld")
    

Vue的动态组件和异步组件

动态组件: Vue提供了一个特殊元素component用来挂在不同的组件,通过改变属性is的值来选择要挂载的组件。

<component :is="currentView"></component>

异步组件:在组件被需要时才开始加载渲染,并把结果缓存起来用于后再再次渲染

Vue.component('async-webpack-example',// 这个动态导入会返回一个 `Promise` 对象。() => import('./my-async-component')
)

Vue-router懒加载

const Foo = () => import('./Foo.vue')const router = new VueRouter({routes: [{ path: '/foo', component: Foo }]
})

Vue运行机制

  1. 初始化 调用原型的_init()进行初始化,初始化生命周期,props,data,methods,computed,watch等,利用Object.definePropty()对data中的属性设置setter和getter函数,实现响应式和依赖收集

  2. 挂载组件 初始化之后调用$mount挂载组件 如果是运行时编译即不存在render函数但存在template需要进行编译步骤

  3. 编译 parse(解析)、optimize(标记静态节点做优化)、generate(转换成字符串)

    parse:利用正则将模板转换为抽象语法树(AST)

    optimize:标记静态节点,以后update的时候,diff算法可以跳过静态节点

    generate:将静态语法树(AST)转换成字符串,供render去渲染DOM

    经过这个步骤组件中就会存在render函数

  4. 响应式:在进行render渲染时会对data进行数据读取,会触发getter函数,把data中的属性进行依赖收集,将这些属性放到观察者(watcher)的观察队列中,当进行属性修改时就会触发setter函数,setter告诉观察者(watcher)数据变化,重新渲染视图,观察者调用update更新视图

  5. 虚拟DOM:render function转换为虚拟DOM,虚拟dom就是一个js对象。render function被转换为VNODe节点。

  6. 更新视图: 在updata时,执行patch将oldNODE传进去,通过diff算法跟VNODE进行比较算出差异然后更新视图。

template解析过程

  • template模板经过parse()生成AST抽象语法树(使用正则解析截取),optimize对静态节点(和数据没有关系,不需要每次更新)优化(diff跳过静态节点,优化patch性能),generate生成render字符串,调用render函数生成DOM
  • 调用new Watcher函数监听数据变化,调用render函数生成vnode
  • 数据更新vnode会与oldnode做diff比较,然后更新dom

nextTick

Vue 在修改数据后,视图不会立刻更新,而是等同一事件循环中的所有数据变化完成之后,再统一进行视图更新。

Vue 实现响应式并不是数据发生变化之后 DOM 立即变化,而是按一定的策略进行 DOM 的更新。$nextTick 是在下次 DOM 更新循环结束之后执行延迟回调,在修改数据之后使用 $nextTick,则可以在回调中获取更新后的 DOM,

Vue生命周期的created()钩子函数进行的DOM操作一定要放在Vue.nextTick()的回调函数中,原因是在created()钩子函数执行的时候DOM 其实并未进行任何渲染,而此时进行DOM操作无异于徒劳,所以此处一定要将DOM操作的js代码放进Vue.nextTick()的回调函数中。与之对应的就是mounted钩子函数,因为该钩子函数执行时所有的DOM挂载已完成。

Vue.nextTick(callback) 使用原理:

原因是,Vue是异步执行dom更新的,一旦观察到数据变化,Vue就会开启一个队列,然后把在同一个事件循环 (event loop) 当中观察到数据变化的 watcher 推送进这个队列。如果这个watcher被触发多次,只会被推送到队列一次。这种缓冲行为可以有效的去掉重复数据造成的不必要的计算和DOm操作。而在下一个事件循环时,Vue会清空队列,并进行必要的DOM更新。
当你设置 vm.someData = ‘new value’,DOM 并不会马上更新,而是在异步队列被清除,也就是下一个事件循环开始时执行更新时才会进行必要的DOM更新。如果此时你想要根据更新的 DOM 状态去做某些事情,就会出现问题。。为了在数据变化之后等待 Vue 完成更新 DOM ,可以在数据变化之后立即使用 Vue.nextTick(callback) 。这样回调函数在 DOM 更新完成后就会调用。

@2.5后版本 $nextTick was using setIwmmediate > MessageChannel > setTimeout

@2.5前版本 $nextTick was using Promise > MutationObserver > setTimeout

https://www.cnblogs.com/purple-windbells/p/11731919.html

Vue优化

  • 路由懒加载
  • 开启服务器Gzip压缩技术,webpack 提供的compression-webpack-plugin进行压缩
  • 使用cdn加速
  • v-if和v-show、computed和watch
  • 列表渲染添加key值
  • 使用keep-aive进行组件缓存
  • 第三方库按需引入 插件babel-plugin-import
  • 服务端渲染 ssr

路由守卫

v-model原理

本质上是v-bind和v-on的结合体,绑定一个value通过v-on触发来更新数据。

主要依赖与Object.defineProperty()这个函数监听get和set事件

实现过程

首先对数据进行劫持监听,设置一个监听器Observer,监听所有的属性。如果属性发生变化就告诉订阅者Watcher是否需要更新。还要有一个消息订阅器Dep收集这些订阅者,在监听器Observer和订阅者Watcher之间统一管理。还需要指令解析器Compile对每个节点元素进行解析,将相关指令对应初始化成一个订阅者Watcher,并替换模板数据或者绑定的函数,Watcher接收到属性变化就执行相关函数更新视图。

1.实现一个监听器Observer,用来劫持并监听所有属性,如果有变动的,就通知订阅者。

2.实现一个订阅者Watcher,可以收到属性的变化通知并执行相应的函数,从而更新视图。

3.实现一个解析器Compile,可以扫描和解析每个节点的相关指令,并根据初始化模板数据以及初始化相应的订阅器。

流程图如下:

function objServer(obj){let keys = Object.keys(obj);keys.forEach((item)=>{definedActive(obj,item,obj[item])})returnobj;
}function definedActive(obj,item,val){Object.defineProperty(obj,item,{get(){console.log(`${item}获取了`)},set(newVlaue){val = newVlaue;console.log(`${item}修改了`)}})
}let obj = objServer({a:1,
b:2
})
obj.a
obj.b
obj.a = 2;
obj.b = 3;

Vue3 proxy的原理

主要通过proxy对对象进行绑定监听处理,通过es6的 new map(自带set和get)对对象的属性进行处理,将要执行的函数匹配到存到对应的prop上,通过每次的访问触发get方法,进行存方法 的操作,通过修改可以触发set方法,接着执行回调监听的函数,达到修改视图和数据。

服务器端渲染 SSR

半静态 后端解析字符串

nuxt 约定式路由

_name.vue动态路由

动态路由 越具体越先匹配

的相关指令,并根据初始化模板数据以及初始化相应的订阅器。

流程图如下:

function objServer(obj){let keys = Object.keys(obj);keys.forEach((item)=>{definedActive(obj,item,obj[item])})returnobj;
}function definedActive(obj,item,val){Object.defineProperty(obj,item,{get(){console.log(`${item}获取了`)},set(newVlaue){val = newVlaue;console.log(`${item}修改了`)}})
}let obj = objServer({a:1,
b:2
})
obj.a
obj.b
obj.a = 2;
obj.b = 3;

Vue3 proxy的原理

主要通过proxy对对象进行绑定监听处理,通过es6的 new map(自带set和get)对对象的属性进行处理,将要执行的函数匹配到存到对应的prop上,通过每次的访问触发get方法,进行存方法 的操作,通过修改可以触发set方法,接着执行回调监听的函数,达到修改视图和数据。

服务器端渲染 SSR

半静态 后端解析字符串

nuxt 约定式路由

_name.vue动态路由

动态路由 越具体越先匹配

asyncData 异步加载数据返回的值会跟data合并

关于react、vue的相关问题相关推荐

  1. vue 新手指引_精通react/vue组件设计之快速实现一个可定制的进度条组件

    前言 这篇文章是笔者写组件设计的第四篇文章,之所以会写组件设计相关的文章,是因为作为一名前端优秀的前端工程师,面对各种繁琐而重复的工作,我们不应该按部就班的去"辛勤劳动",而是要根 ...

  2. 如何命令行结束react程序_想要成为前端Star 吗?一首歌时间将React / Vue 应用Docker 化...

    前言 以前一直有疑问困扰着我:人人都在吹的Docker容器化,与前端有何关系? 然而在近两年的编程生涯,在每一次产品迭代中,渐渐体会到了容器化其魅力所在. 应用部署从刀耕火种,到DevOps崛起,原来 ...

  3. docker web程序本地化_想要成为前端Star 吗?一首歌时间将React / Vue 应用Docker 化...

    前言 以前一直有疑问困扰着我:人人都在吹的Docker容器化,与前端有何关系? 然而在近两年的编程生涯,在每一次产品迭代中,渐渐体会到了容器化其魅力所在. 应用部署从刀耕火种,到DevOps崛起,原来 ...

  4. 【华为云技术分享】三大前端技术(React,Vue,Angular)探密(下)

    [华为云技术分享]三大前端技术(React,Vue,Angular)探密(上) [Angular] Angular(通常被称为 "Angular 2+"或 "Angula ...

  5. 【华为云技术分享】三大前端技术(React,Vue,Angular)探密(上)

    [引言] 前段时间写过一篇关于前端技术的概括性文章<前端技术的选择]>(http://3ms.huawei.com/km/blogs/details/7971337),本文就对于当下顶级的 ...

  6. vue如何写原生js_纯技巧向:React, Vue, Rxjs 和原生 JS 代码大乱斗

    前言 这是一篇纯技巧向的文章,跟一年多之前的<揭秘Vue-3.0最具潜力的API>一样[0],更少的背景铺垫,更多的代码,更多的 demo,更快的节奏. 让我们直接进入主题. 背景 前一阵 ...

  7. RxJS/Cycle.js 与 React/Vue 相比更适用于什么样的应用场景?

    RxJS/Cycle.js 与 React/Vue 相比更适用于什么样的应用场景? RxJS/Cycle.js 与 React/Vue 相比更适用于什么样的应用场景? - 知乎 https://www ...

  8. 前端vue适配不同的分辨率_浅析 React / Vue 跨端渲染原理与实现

    当下的前端同学对 React 与 Vue 的组件化开发想必不会陌生,RN 与 Weex 的跨界也常为我们所津津乐道.UI 框架在实现这样的跨端渲染时需要做哪些工作,其技术方案能否借鉴乃至应用到我们自己 ...

  9. 【转】React Vue MVC MVVM MVP

    首先,在谈这个话题之前, 我们有必要了解一下库和框架的区别. 我们先来看react官网以及vue官网对他们的定位: react: vue: react我们不说了,官网上明明白白说了,人家是一个libr ...

  10. vue 图片被背景色覆盖_如何使用纯css3打造有点意思的故障艺术(附React/Vue加强组件版)...

    前言 很早之前就看到国外很多酷炫的网站在实践"故障艺术", 或者错位动画", 感觉非常有意思, 现在APP端的抖音启动界面有着这种设计的影子, 作为一名用于探索未知的前端 ...

最新文章

  1. 转载----Python的zip()函数
  2. pixhawk position_estimator_inav.cpp思路整理及数据流
  3. VC连接mysql数据库错误:libmysql.lib : fatal error LNK1113: invalid machine 解决方法
  4. HTML+CSS+JS实现 ❤️酷炫3D瀑布流动画特效❤️
  5. 计算机类自主招生推荐信,自主招生推荐信范文:中国人民大学自主招生推荐信...
  6. 怎么将ip地址改成域名访问_什么是域名解析?怎么把域名解析成IP地址?
  7. Jenkins分布式构建和部署(master-slave)
  8. 在Android平台上发现新的恶意程序伪装成杀毒软件挟持设备
  9. 博弈论 从懵逼到入门 详解
  10. 简单易懂的Android ROM定制与修改教程
  11. api 原生hbase_HBase实践 | BDSHBase数据迁移同步方案的设计与实践
  12. foobar2000 常用插件搜集
  13. ip地址切换 线路切换 网吧线路切换器 ip地址切换器
  14. 白嫖JetBrains全家桶第二波与第三波
  15. 天下大事,必做于细!
  16. kodi mysql_Kodi
  17. dts,dtb,dtc
  18. 蓝桥杯泊松分酒java_蓝桥杯-泊松分酒 - steven_wjg的个人空间 - OSCHINA - 中文开源技术交流社区...
  19. 找不到gpedit.msc文件
  20. windows版redis安装教程(2022)

热门文章

  1. 【java毕业设计】基于javaEE+SSH+mysql的医院在线挂号系统设计与实现(毕业论文+程序源码)——医院在线挂号系统
  2. VC/MFC 编程经验
  3. 远程办公和分布式协作
  4. HTC Vive开发笔记之手柄震动
  5. 手机信令数据怎么获得_运用手机信令数据研究大都市区空间结构 ——以南昌大都市区为例...
  6. NOIP2016普及组复赛——T4魔法阵
  7. 进不去jetbrain官网怎么办
  8. PVR图像文件格式初探
  9. 【SAP】在制品报表 查询及结算余额查询
  10. UltraVNC:一款高层玩家使用的远程控制软件