vuejs / docs

📄 Documentation for Vue 3

Home Page:https://vuejs.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Add a note or caution to the documentation for the `customRef` function.

demershov opened this issue · comments

I encountered an issue with the customRef function, where it wasn't working as i expected.
First of all, I would like to note that I have already discussed this issue with @LinusBorg and @skirtles-code in the community chat. I've come to the conclusion that although this is the expected behavior for customRef, it would be beneficial to add additional information to the documentation for other developers like me.

If a get() method inside the customRef returns an object that is the same as the previous value but is newly generated, then components that accept this customRef as a prop will perceive the new object as modified value. It is important to note that the trigger will not happen inside the set() method.

Steps to reproduce:

  1. Declare a variable using the customRef in a parent component.
  2. Pass this variable as prop for the child component.
  3. Change another sibling component in the parent component that is not associated with this variable.
  4. The parent component is re-rendered, but since the variable declared using customRef is tracks by the parent component render effect, the get() in the customRef is called again, and the getter, in turn, returns a new object but with the same shape.
  5. For the child component, this will be a new object and the child component will be re-rendered, even though the props haven't been explicitly changed.
  6. If will add a watcher for this variable inside the parent component, then the watcher will not trigger a callback, because the trigger function was not called inside a set() of the customRef.

Link to the Playground

I've also created an issue at vueuse/vueuse#3992 as the useRouteQuery also suffers from this behavior.

Thanks.

Hello, thank you for logging this.

I have tested this in the Playground and confirmed the unexpected behavior. Here’s a breakdown of what happens:

  • Change Unrelated State: An unrelated state change in the parent component triggers its render function.
  • Component Re-render: This causes the parent component to re-render, which includes re-evaluating Comp.vue.
  • Evaluate CustomRef: The customRef's get() method is called again, returning a new object with the same structure as the previous value.
  • Prop Comparison: During re-rendering, Vue compares the new and previous props of the child component.
  • Perceived Prop Change: Although the objects are structurally identical, they are different instances. Vue perceives this as a prop change.
  • Child Component Re-render: This perceived prop change triggers the child component to re-render and its watchers to react, despite no actual change in the logical state.
  • This behavior occurs because the customRef does not trigger updates inside its set() method, leading to reactivity issues when the getter returns a new object instance.

Let me know if this is the case per your deductions.

Hello @seeniOlabode
Yes, it seems that this is the case.

If you or someone takes a closer look, you will understand why this happens. However, I believe it would be beneficial to include this information in the documentation.

Thank you for your attention.