V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
llbbzh
V2EX  ›  问与答

在 Vue 里, props 传入 Object 或 Array 的最佳实践是什么?

  •  
  •   llbbzh · 307 天前 · 783 次点击
    这是一个创建于 307 天前的主题,其中的信息可能已经有所发展或是发生改变。

    如果一个 Vue 组件接受一个 Object 或者 Array 作为 prop ,那在这个组件内部处理该 prop 时就会有很多种写法,我很好奇,到底哪种是最佳实践呢?

    从组件使用该 prop 的方式来看,可以分成两种类型:

    • 外部状态型。 就是直接拿 prop 值来渲染,修改时也直接修改原 prop 内部的内容。比如,我写了个表格组件,在里面直接用 v-for 遍历 prop 里的数组来显示表格的每一行。
    • 内部状态型。 就是内部还有一个 ref/data 值,其初始值为传入的 prop 。如果要修改数据,则仅修改内部的 ref/data ,然后通过一些方式与外部的 prop 同步。比如,我写了个表格组件,我在 created 时把 prop 复制一遍,模板里 v-for 遍历的是我复制过的这个数组。然后我 watch 外部 prop ,如果它变化了,我就再复制一遍。

    从组件向外发布新数据的方式看,又能分成三种类型:

    • 直接修改型。 就是组件把 prop object / array 里面的元素或者属性直接绑定到 v-model 上,或者直接用 JS 改外部传进来的 prop 值。我在 vue-element-admin 里见过这种操作,里面有个组件可以开关表格的各个列,然后用这个组件时只需要把记录各个列开关状态的数组用 prop 传进去,不需要监听 update 事件。
    • 修改后通知型。 指的是组件会直接修改 prop object / array 里面的元素,但是修改完之后会触发 emit 事件,把 prop 值原封不动地 emit 出去。
    • 不可变对象型。 指组件永远不直接修改外部 prop ,而是每次修改前都把整个对象(或数组)克隆一遍,修改新的对象,再通过 emit update 事件把新的对象传出去。

    这几种写法各有优缺点,你的项目用的是什么写法?最推荐的写法到底是啥?

    8 条回复    2023-07-12 09:34:31 +08:00
    ruoxie
        1
    ruoxie  
       307 天前   ❤️ 1
    vue react 都写的用的是不可变对象型
    x02
        2
    x02  
       307 天前   ❤️ 1
    可以简化为, 组件是否修改 prop 中的对象, 如果修改, 如何通知父组件.

    1. 如果组件不修改 prop 对象, 当然可以直接使用, 如果你是函数式原教旨主义者, 你还可以克隆一遍
    2. 当 prop 近乎于组件独有的状态时, 可以直接修改, 例如表格列开关状态, 这个状态除了这个表格, 其他地方不会用到.
    3. 如果外部需要知道有状态产生变化, 但并不依赖该状态的值, 可以修改后通知. 比如有一个更新视口的函数, 在表格列开关后, 它会更新页面宽度. 这个函数并不在乎具体哪个列产生了变化.
    4. 当状态被多个地方依赖时, 用不可变对象会更加稳健. 所有的组件只修改克隆版, 修改后 emit 新的值.
    5. 可以无脑用不可变对象. 啰嗦且性能也不好.
    ChefIsAwesome
        3
    ChefIsAwesome  
       307 天前   ❤️ 1
    比方讲你把一个组件里的一部分拆出来变成一个子组件。你不是为了复用功能,而是为了分解逻辑才拆分。拆分之前,对子组件这部分代码来说,它修改 data(state)。所以没有理由一模一样的代码,放到新文件里就要做事件、克隆之类的操作,直接修改 prop 就对了。
    另外 vue 的事件是一对一的。父组件订阅子组件事件,等同于父组件传一个函数给子组件执行。
    vivipure
        4
    vivipure  
       307 天前   ❤️ 1
    虽然官方推荐不要直接修改 props , 但实际应用中,如果传入的是引用的话,子组件修改也无所谓的。反正 Vue 是有依赖收集的,并不强调不可变性。
    在常见的表单场景下,我就习惯将部分独立的属性,用子组件拆分进行控制。修改后再通知实在繁琐,且没多大必要。
    mineralsalt
        5
    mineralsalt  
       307 天前
    我也很好奇这两种写法哪个对? 我一般都用第 2 个, 因为可以传入基本类型和自定义对象
    1: defineProps({val: Number})
    2:: defineProps<{val: number}>()
    tianzi123
        6
    tianzi123  
       305 天前
    你写的貌似有问题吧 , 内部状态型 里说 用 watch 监听/? 如果用了 ref 为啥不用 const data = toRef(data) 直接 就是响应式的,另外单项数据流我觉得还是要遵守,这是一个良好的书写习惯,特别是团队合作,虽然有时候可以偷懒,但不利于长期维护
    tianzi123
        7
    tianzi123  
       305 天前
    @tianzi123 另外,父组件的数据一般都是调接口获取,我个人写法,一般都是 子组件更新值了,直接通知父组件重新调用接口获取,这样最省事也符合规范,特别是弹窗多的页面,比如说一个页面 10 个弹窗,父组件一个更新函数搞定
    charlie21
        8
    charlie21  
       296 天前
    @Livid may be worth moving to /go/vue
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2280 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 15:16 · PVG 23:16 · LAX 08:16 · JFK 11:16
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.