这个题目很有难度,首先思考vuex
解决的问题:存储用户全局状态并提供管理状态API。
vuex
需求分析官方说vuex
是一个状态管理模式和库,并确保这些状态以可预期的方式变更。可见要实现一个vuex
:
Store
存储全局状态commit(type, payload)
, dispatch(type, payload)
实现Store
时,可以定义Store类,构造函数接收选项options,设置属性state对外暴露状态,提供commit和dispatch修改属性state。这里需要设置state为响应式对象,同时将Store定义为一个Vue插件。
commit(type, payload)
方法中可以获取用户传入mutations
并执行它,这样可以按用户提供的方法修改状态。 dispatch(type, payload)
类似,但需要注意它可能是异步的,需要返回一个Promise给用户以处理异步结果。
Store的实现:
class Store { constructor(options) { this.state = reactive(options.state) this.options = options } commit(type, payload) { this.options.mutations[type].call(this, this.state, payload) } }
Vuex中Store的实现:
https://github1s.com/vuejs/vuex/blob/HEAD/src/store.js#L19-L20
mutations
和actions
是vuex
带来的两个独特的概念。新手程序员容易混淆,所以面试官喜欢问。
我们只需记住修改状态只能是mutations
,actions
只能通过提交mutation
修改状态即可。
看下面例子可知,Action
类似于 mutation
,不同在于:
Action
提交的是 mutation
,而不是直接变更状态。Action
可以包含任意异步操作。const store = createStore({ state: { count: 0 }, mutations: { increment (state) { state.count++ } }, actions: { increment (context) { context.commit('increment') } } })
mutation
,mutation
非常类似于事件:每个 mutation
都有一个字符串的类型 (type)*和一个*回调函数 (handler)。Action
类似于 mutation
,不同在于:Action
可以包含任意异步操作,但它不能修改状态, 需要提交mutation
才能变更状态。{commit, dispatch, state}
,从而方便编码。另外dispatch会返回Promise实例便于处理内部异步结果。options.mutations[type](state)
;dispatch(type)
方法相当于调用options.actions[type](store)
,这样就很容易理解两者使用上的不同了。我们可以像下面这样简单实现commit
和dispatch
,从而辨别两者不同:
class Store { constructor(options) { this.state = reactive(options.state) this.options = options } commit(type, payload) { // 传入上下文和参数1都是state对象 this.options.mutations[type].call(this.state, this.state, payload) } dispatch(type, payload) { // 传入上下文和参数1都是store本身 this.options.actions[type].call(this, this, payload) } }
企业级项目中渲染大量数据的情况比较常见,因此这是一道非常好的综合实践题目。
v-once
方式只渲染一次v-for
使用,避免数据变化时不必要的VNode创建vuex数据状态是响应式的,所以状态变视图跟着变,但是有时还是需要知道数据状态变了从而做一些事情。
既然状态都是响应式的,那自然可以watch
,另外vuex也提供了订阅的API:store.subscribe()
。
总述知道的方法
分别阐述用法
选择和场景
我知道几种方法:
watch选项方式,可以以字符串形式监听$store.state.xx
;subscribe方式,可以调用store.subscribe(cb),回调函数接收mutation对象和state对象,这样可以进一步判断mutation.type是否是期待的那个,从而进一步做后续处理。
watch方式简单好用,且能获取变化前后值,首选;subscribe方法会被所有commit行为触发,因此还需要判断mutation.type,用起来略繁琐,一般用于vuex插件中。
watch方式
const app = createApp({ watch: { '$store.state.counter'() { console.log('counter change!'); } } })
subscribe方式:
store.subscribe((mutation, state) => { if (mutation.type === 'add') { console.log('counter change in subscribe()!'); } })
vue-router中两个重要组件router-link
和router-view
,分别起到导航作用和内容渲染作用,但是回答如何生效还真有一定难度哪!
router-link
和router-view
,分别起到路由导航作用和组件内容渲染作用https://github1s.com/vuejs/router/blob/HEAD/src/RouterLink.ts#L184-L185
https://github1s.com/vuejs/router/blob/HEAD/src/RouterView.ts#L43-L44