简介
Vuex
和Redux
应该是我们前端开发用得最多的两个状态管理库了。那么这两者到底有哪些相同点和不同点呢?今天我们再来对比总结下。
希望通过这种对比方式的学习能让我们学习的时候印象更深刻,希望能够帮助到大家。
安装
Vuex直接安装就可以使用
npm i vuex
Redux在React中使用还需要使用React-Redux
在React
中单使用Redux
是不行的,还需要借助React-Redux
。React-Redux
类似一个桥梁将Redux
和React
连接起来。
npm i redux react-redux
整体结构
Vuex主要分为四大块
在Vuex
中,主要分为state、getters、mutations、actions
四大块。
state
定义状态。getters
是状态的计算属性,状态改变自动会重新计算。mutation
用来同步修改state
。也是唯一能修改state
的地方。actions
用来进行异步操作,并且还可以提交mutation
或action
。
// module1.js
{
// 状态
state: {
userinfo: {}
},
// 计算属性,状态改变自动会重新计算
gertters: {
getterUserInfo(state, getters, rootState, rootGetters) {
return state.userinfo
}
},
// 同步修改state
mutations: {
setUserInfo(state, payload) {
state.userinfo = payload
}
},
// 进行异步操作,每个action的返回值都是一个promise
// 还可以提交mutation或action
actions: {
async getUserInfoAction({ dispatch, commit, state, rootState, getters, rootGetters }, payload) {
// 异步请求获取结果
const response = await fetch(
`https://jsonplaceholder.typicode.com/todos/${payload}`
);
const result = response.json()
// 提交 mutation
commit(setUserInfo, result)
// 返回值会被promise包裹
return result
}
},
}
当store
达到一定规模后我们还会启用modules
或namespaced
来进行更精细化的管理。
当启用modules
后store
总体目录如下
store
├── modules
│ ├── module1.js
│ └── module2.js
└── index.js
根模块
// index.js
{
// 根状态
state: {
userinfo: {}
},
// 根getters
gertters: {},
// 根mutations
mutations: {},
// 根actions
actions: {},
// 模块,当系统庞大后一般会启用模块功能
modules: {
module1: module1,
module2: module2
},
}
当只启用了module
后,state
会通过模块来获取,上面的例子this.$store.state.userinfo
获取用户信息会变为this.$store.state.module1.userinfo
。但是getters、mutations、actions
的获取方式不受影响。
当启用了module
并且子模块启用了namespaced
,则getters、mutations、actions
也会通过模块来获取。上面的例子this.$store.getter.getterUserInfo
会变为this.$store.getter['module1/getterUserInfo']
。mutations、actions
也是类似,会加上模块名。
// module1.js
{
// 命名空间,当设置为true后,getters mutations actions都会按模块来处理
namespaced: true
}
当启用namespaced
后,该模块的action
只能提交本模块的mutation
和action
,不能提交其它模块的mutation
和action
,如果要提交需要传递第三个参数root: true
。
commit("其它模块的mutation", payload, { root: true });
dispatch("其它模块的action", payload, { root: true });
当启用namespaced
后,如果想创建全局的action,需要使用对象形式的写法,并传递root: true
。
// 注册非命名空间的action
// root: true,
setGlobalGoodsAction: {
root: true,
handler: ({ commit }) => {
commit("setGoodsNameMutation", "我是全局action,提交我不用带命名空间");
},
}
这个action
就会被注册到根模块下,不需要通过模块名来获取。
Redux主要分为三大块
Redux
中主要分为state、actions、reducers
三大块
state // 定义状态,一般定义在reducer中
actions // 传递type和payload参数
reducers // 改变 state 的唯一方法,必须为纯函数,判断 action 的type相应更新state。每次 reducer 都是返回一个全新的 state。
Redux
没有Vuex
那么聚合,各个模块分离的比较散,都是单独的文件,不用写在一个文件中。
action1.js
export const setUserInfoAction(payload) {
return {
type: 'setuserinfo',
payload
}
}
reducer1.js
,在Redux
中,state
一般会定义在reducer中。
const initialState = { userinfo: {}}
export default function(state=initialState, action) {
switch(action.type) {
case 'setuserinfo':
return {...state, userinfo: action.payload}
default:
return state
}
}
当store
达到一定规模后我们会创建多个reducer
然后使用combineReducers()
来讲他们组合起来。
Redux
的store
总体目录如下
store
├── actions
│ ├── action1.js
│ └── action2.js
├── reducers
│ ├── reducer1.js
│ └── reducer2.js
├── types.js
└── index.js
创建
Vue通过createStore方法创建store
通过createStore
方法并传递根模块创建store
实例。
import { createStore } from "vuex";
export default createStore({
state: {},
getters: {},
mutations: {},
actions: {},
modules: {
// 这面是子模块
}
})
然后通过Vue
的use
方法,以插件形式进行使用。
import { createApp } from "vue";
const app = createApp(App);
app.use(store).mount("#app");
React通过createStore方法创建store
React
通过Redux
的createStore
方法传递所有的reducers
创建store
。
import { createStore } from "redux";
const store = createStore(redicers);
然后通过React-Redux
的Provider
组件传递store
进去,将React
和Redux
连接在一起。
import { Provider } from "react-redux";
<Provider store={store}>
<App />
</Provider>
使用
Vue中可以直接使用
// vue2
// this.$store.state // 获取state
// this.$store.getter // 获取getter
// this.$store.commit() // 提交mutation
// this.$store.dispatch() // 提交action
// vue3
import {useStore} from 'vuex'
const store = useStore()
// store.state // 获取state
// store.getter // 获取getter
// store.commit() // 提交mutation
// store.dispatch() // 提交action
React中需要借助React-Redux的connect方法
// 类组件
// 通过react-redux的connect方法参数mapStateToProps将state定义到组件的props属性上。
mapStateToProps(state) {
return {
userinfo: state.reducer1.userinfo
}
}
// 通过react-redux的connect方法参数mapDispatchToProps将dispatch方法传递进来。
mapDispatchToProps(dispatch) {
return {
handleSetUserInfo() {
dispatch(getUserInfoAction(1))
}
}
}
// 函数组件
// 函数组件通过react-redux的useSelector和useDispatch两个hook
const userinfo = useSelector((state) => state.reducer1.userinfo);
const dispatch = useDispatch();
dispatch(getUserInfoAction(1))
异步方案
异步一般就是我们向后端发送请求获取数据的过程。
Vuex直接支持异步
在Vuex
中,我们的异步操作可以直接定义在action
中,当异步有了结果再提交mutation
来同步修改state
。
Redux需要借助中间件
在Redux
中因为action
只能返回普通的对象所以是不支持直接使用异步的。如果要使用异步,需要借助redux-thunk、redux-promise、redux-saga
等第三方中间件。
具体使用可以查阅笔者前面写的Redux 异步数据流方案对比(redux-thunk、redux-promise、redux-saga),这里就不再细说了。
数据流
在数据流方面,Vuex
和Redux
都是单仓库单向数据流。也就是数组仓库store
只会有一个,并且都只能在触发相应action
后,在reducer
或mutaion
里面才能修改state
,是一个单向数据流。
Vuex
和Redux
都是只能在特定地方修改state
。Vuex
只能在mutation
中修改,Redux
只能在reducer
中修改。
Redux
中不能直接修改原state
,reducer
必须是纯函数,每次返回新的state
。在Vuex
中mutation
里面是可以对state
直接修改的。
同步数据流
在Vuex
中同步数据流是commit mutation -> 进入到mutation方法直接修改state
在Redux
中同步数据流是dispatch action -> 进入到reducer匹配type进行相应处理返回新的state
异步数据流
在Vuex
中异步数据流是dispatch action -> 进入到action进行异步请求 -> 请求有了结果commit mutation -> 进入到mutation方法修改state
在Redux
中异步数据流是dispatch action -> 进入到异步中间件进行异步请求 ->请求有了结果进入reducer匹配type进行相应处理返回新的state
总结
Vuex
安装后直接使用,Redux
在React
中使用还需要借助React-Redux
。Vuex
中state、getters、mutations、actions
集中在一个文件,并各司其职。Redux
相对来说较为分散,state、actions、reducers
定义在不同的文件中,对于初学者来说可能没那么好理解。但是可以使用Redux Toolkit
来简化Redux
的使用,使用Redux Toolkit
后就会有在使用Vuex
的感觉,想了解更多的话可以看看笔者前面写的对比React-Redux看看Redux Toolkit有哪些优点。Vuex
内可以直接使用异步,但是Redux
需要借助redux-thunk、redux-promise、redux-saga
等中间件。Vuex
在mutation
里面是直接修改state
,但是Redux
在reducer
里面每次必须返回新的state
。Vuex
里面是支持getter
计算属性的,但是Redux
不支持。
系列文章
Vue和React对比学习之生命周期函数(Vue2、Vue3、老版React、新版React)
Vue和React对比学习之组件传值(Vue2 12种、Vue3 9种、React 7种)
Vue和React对比学习之路由(Vue-Router、React-Router)
Vue和React对比学习之状态管理 (Vuex和Redux)
Vue和React对比学习之条件判断、循环、计算属性、属性监听
后记
感谢小伙伴们的耐心观看,本文为笔者个人学习笔记,如有谬误,还请告知,万分感谢!如果本文对你有所帮助,还请点个关注点个赞~,您的支持是笔者不断更新的动力!