Vuex如何将模块state属性映射为独立的组件计算属性
问题原因
你将charactersModule作为子模块注册到Vuex根store时,模块的state会默认挂载在根state对应模块名的字段下,根state实际结构为:
{ characters: { // 这就是你写mapState(['characters'])拿到的整个模块state对象 characters: [], isLoading: false, totalPages: 0, currentPage: 1, itemsPerPage: ITEMS_PER_PAGE } }
直接使用mapState(['characters'])只会把这个嵌套的模块state对象映射为单个计算属性,不会自动展开内部字段为独立计算属性。
实现方案
两种可落地的写法,优先选择第二种(开启命名空间的模块化写法是Vuex官方推荐的最佳实践,可避免多模块命名冲突):
方案1:不开启命名空间,手动映射嵌套属性
如果不需要给模块开启命名空间,给mapState传对象形式的配置,逐个指定每个计算属性的取值路径即可:
computed: { ...mapState({ characters: state => state.characters.characters, isLoading: state => state.characters.isLoading, totalPages: state => state.characters.totalPages, currentPage: state => state.characters.currentPage, itemsPerPage: state => state.characters.itemsPerPage }), // 组件自有计算属性写在后面 }, methods: { // 不开命名空间时action挂载在全局,原有mapActions写法不用改 ...mapActions(['getCharacters']), }
方案2:给模块开启命名空间(推荐)
首先修改模块定义,加上namespaced: true标记:
const charactersModule = { namespaced: true, // 开启命名空间 state: () => ({ characters: [], isLoading: false, totalPages: 0, currentPage: 1, itemsPerPage: ITEMS_PER_PAGE, }), getters: {}, mutations: {}, actions: { // 原有action逻辑保持不变即可 async getCharacters({state}, page = state.currentPage) { try { state.isLoading = true; const res = await fetch(`${BASE_URL}character/?page=${page}`); if (res.ok) { const { info, results } = await res.json(); state.characters = results; } } catch (e) { console.log(e); } finally { state.isLoading = false; } }, }, }; // store注册逻辑保持不变 export default createStore({ modules: { characters: charactersModule, }, });
组件中映射时给mapState、mapActions传入第一个参数指定模块名,就可以直接把模块内的state、action映射为组件的独立属性/方法:
methods: { ...mapActions('characters', ['getCharacters']), }, computed: { ...mapState('characters', ['characters', 'isLoading', 'totalPages', 'currentPage', 'itemsPerPage']) }, mounted() { this.getCharacters() },
补充注意:你当前在action中直接修改state的写法,在Vuex严格模式下会抛出错误,建议将状态修改逻辑收敛到mutations中,action只负责异步请求、提交mutation修改状态,符合Vuex的状态流转规范。
内容的提问来源于stack exchange,提问作者qweezz
相关产品推荐
相关产品推荐

