Why using toRef(props) and is it good idea to change their value in CompositionAPI?
Asked Answered
A

2

9

I've seen a pattern of using props in of CompositionAPI very often, that is use toRefs to make all entries of props ref. I'm kind of confused by it.

For exmaple, from the Vue 3 official guide:

export default {
  props: {
    user: {
      type: String,
      required: true
    }
  },
  setup(props) {
    const { user } = toRefs(props)

    //... use user's value
  }
}

I have 2 questions in 2 scenearios:

  1. when the props.user is already reactive
    Its value will change if it's changed in any ancestors, so why we need to use toRefs? Doesn't it already reactive?

  2. if it's not reactive, it's just a primitive string value
    Does making it reactive means we're going to change its value? I think making a object reactive also imply that its value is welcomed to be changed. But all the guides and linters warn us that we'd better not to change the props value.(for not writing to the computed value or something)

If I can change the props value directly in the component, I no longer need to emit the changes to parent component everytime. It's very convenient but I don't know whenther it is a good idea to change the props value after we're sure it becomes reactive?

Amr answered 1/10, 2021 at 16:23 Comment(1)
I don't see how it can be anything other than an antipattern. You're still affecting the parent without the parent knowing about it. props are meant to be read-only, and converting them to refs might lead to unintended mutations etc.Hf
A
6

Since props aren't supposed to be mutated, this is useful for a specific case that is explained in the documentation; a ref that is computed from a prop needs to be passed as an argument:

const { user } = toRefs(props)
// or
// const user = computed(() => props.user)

someFunction(user);

Where a function makes use of composition API or just needs an argument to be passed by reference rather than by value due to the way it works, e.g.:

function someFunction(val) {
  setTimeout(() => {
    console.log('Up-to-date value:', unref(val));
  }, 1000);
}
Accusal answered 1/10, 2021 at 17:47 Comment(3)
Then what is the diffenence if we pass props.user to someFunction? Why should we use toRefs here? Sorry if I missed anything.Damiano
What is the different between pass by value and pass by reference here?Damiano
When passing by value you'll capture val value at the time when someFunction was called and will use stale value inside setTimeoutAccusal
H
1

props should not be assigned toRef (with some limited exceptions:)

enter image description here

enter image description here

(both from vuejs.org, see link below)

In the VueJS toRef docs it explicitly states:

When toRef is used with component props, the usual restrictions around mutating the props still apply. Attempting to assign a new value to the ref is equivalent to trying to modify the prop directly and is not allowed. In that scenario you may want to consider using computed with get and set instead. See the guide to using v-model with components for more information.

so, in answer to your questions:

Only the parent should be able to modify the variables supplied to its child's props. a prop is a getter in the child, nothing more. if you make it reactive in the child, you could cause side effects in the parent without the parent knowing about it. This is why we explicitly use event emissions to make it clear to the parent what is going on and when

Hf answered 11/9 at 13:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.