MST

星途 面试题库

面试题:Vuex中如何优化复杂嵌套状态结构的读取

在Vue项目里,假设存在一个多层嵌套的状态结构,比如一个电商系统中商品分类下又有不同品牌,品牌下还有不同型号的商品列表等类似结构。请阐述在Vuex中你会采用哪些方法来优化对这种复杂嵌套状态的读取操作,以提高代码的可读性和性能,并举例说明。
14.9万 热度难度
前端开发Vue

知识考点

AI 面试

面试题答案

一键面试
  1. 使用Getter函数
    • 阐述:Getter 可以对 Vuex 中的状态进行加工处理,将复杂的嵌套状态读取逻辑封装起来,提高代码的可读性。并且,由于 Getter 会自动缓存,只有在它依赖的状态发生变化时才会重新计算,所以也能提升性能。
    • 示例
    // store.js
    const state = {
        productCategories: [
            {
                id: 1,
                name: '电子产品',
                brands: [
                    {
                        id: 11,
                        name: '苹果',
                        models: [
                            { id: 111, name: 'iPhone 14' },
                            { id: 112, name: 'MacBook Pro' }
                        ]
                    },
                    {
                        id: 12,
                        name: '华为',
                        models: [
                            { id: 121, name: 'P60' },
                            { id: 122, name: 'MateBook X' }
                        ]
                    }
                ]
            }
        ]
    };
    const getters = {
        getProductModelsByBrand: state => brandId => {
            return state.productCategories.reduce((acc, category) => {
                const brand = category.brands.find(b => b.id === brandId);
                if (brand) {
                    return brand.models;
                }
                return acc;
            }, []);
        }
    };
    export default new Vuex.Store({
        state,
        getters
    });
    // 在组件中使用
    import { mapGetters } from 'vuex';
    export default {
        computed: {
            ...mapGetters(['getProductModelsByBrand']),
            appleModels() {
                return this.getProductModelsByBrand(11);
            }
        }
    };
    
  2. 规范化数据结构
    • 阐述:尽量将嵌套的数据结构扁平化为更容易读取的形式。比如使用对象来存储数据,以 ID 作为键,这样可以直接通过键来获取所需的数据,而不需要进行多层遍历。
    • 示例
    // 规范化前
    const state1 = {
        productCategories: [
            {
                id: 1,
                name: '电子产品',
                brands: [
                    {
                        id: 11,
                        name: '苹果',
                        models: [
                            { id: 111, name: 'iPhone 14' },
                            { id: 112, name: 'MacBook Pro' }
                        ]
                    }
                ]
            }
        ]
    };
    // 规范化后
    const state2 = {
        productCategories: {
            1: {
                id: 1,
                name: '电子产品'
            }
        },
        brands: {
            11: {
                id: 11,
                name: '苹果',
                categoryId: 1
            }
        },
        models: {
            111: { id: 111, name: 'iPhone 14', brandId: 11 },
            112: { id: 112, name: 'MacBook Pro', brandId: 11 }
        }
    };
    const getters2 = {
        getProductModelsByBrand: state => brandId => {
            return Object.values(state.models).filter(model => model.brandId === brandId);
        }
    };
    
  3. 模块分割
    • 阐述:将复杂的状态按照功能模块进行分割,每个模块维护自己的状态、Getter、Mutation 和 Action。这样可以使代码结构更清晰,对不同部分的状态读取也更加明确,避免相互干扰。
    • 示例
    // productCategory.js
    const state = {
        list: []
    };
    const getters = {
        getCategoryById: state => id => {
            return state.list.find(category => category.id === id);
        }
    };
    export default {
        namespaced: true,
        state,
        getters
    };
    // brand.js
    const state = {
        list: []
    };
    const getters = {
        getBrandById: state => id => {
            return state.list.find(brand => brand.id === id);
        }
    };
    export default {
        namespaced: true,
        state,
        getters
    };
    // 在 store.js 中整合
    import Vuex from 'vuex';
    import productCategory from './productCategory';
    import brand from './brand';
    export default new Vuex.Store({
        modules: {
            productCategory,
            brand
        }
    });
    // 在组件中使用
    import { mapGetters } from 'vuex';
    export default {
        computed: {
            ...mapGetters('productCategory', ['getCategoryById']),
            ...mapGetters('brand', ['getBrandById'])
        }
    };