llbbzh
V2EX  ›  问与答

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

  •  
  •   llbbzh · Jul 1, 2023 · 1582 views
    This topic created in 1047 days ago, the information mentioned may be changed or developed.

    如果一个 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 replies    2023-07-12 09:34:31 +08:00
    ruoxie
        1
    ruoxie  
       Jul 1, 2023   ❤️ 1
    vue react 都写的用的是不可变对象型
    z4oSkDNGGC2svsix
        2
    z4oSkDNGGC2svsix  
       Jul 1, 2023   ❤️ 1
    可以简化为, 组件是否修改 prop 中的对象, 如果修改, 如何通知父组件.

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