Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

beforeUpdate timing, attrs and setup #1899

Closed
skirtles-code opened this issue Aug 19, 2020 · 0 comments
Closed

beforeUpdate timing, attrs and setup #1899

skirtles-code opened this issue Aug 19, 2020 · 0 comments

Comments

@skirtles-code
Copy link
Contributor

Version

3.0.0-rc.5

Reproduction link

https://jsfiddle.net/skirtle/nr9j42mb/34/

Steps to reproduce

  1. Open the console log.
  2. Click the button.
  3. Observe the error message.

The error reads:

Error: Maximum recursive updates exceeded. You may have code that is mutating state in your component's render function or updated hook or watcher source function.

The error message is slightly misleading as the state mutation actually happens in a beforeUpdate hook. But to my mind that
isn't the real problem here.

In brief, perhaps I'm missing something but as far as I can tell:

  1. The beforeMount and beforeUpdate hooks now run after render, not before.
  2. There doesn't seem to be any way to react to changes in attrs within setup prior to the rendering update.

What is expected?

My own expectation would be for beforeMount and beforeUpdate to be called prior to render, as they were with Vue 2.

Failing that I can't see any way to react to attr changes in setup.

What is actually happening?

beforeUpdate is called too late to make the relevant state update.


Here's the reasoning behind the code:

  1. The code is trying to partition attrs into two sets of attributes. One set is used on the root node and the other is used on an inner <input>.
  2. I don't believe it's possible to use props to perform the partitioning because we can't have a prop for all data- attributes. The use of data- here is somewhat arbitrary, it could just as easily be prefixed listeners being sent to different child elements.
  3. The code is using setup. If you don't use setup it is trivial to fix using computed properties and this.$attrs. The point here is trying to implement it with setup.
  4. There doesn't seem to be any documented way to access the reactive property this.$attrs from within setup. It can be done with getCurrentInstance().proxy.$attrs but that isn't documented.
  5. The attrs provided by the setup context object is not reactive.
  6. It isn't possible to use attrs in a computed ref because it isn't reactive.
  7. onBeforeUpdate seems like a natural place to sync the state based on attrs.

The problem is that onBeforeUpdate runs after render, which is too late. The attempt to update that state based on attrs gets in an infinite update loop.

I tried onRenderTriggered and onRenderTracked too but neither of them is called at the right time for this scenario.

There are ways to rewrite the code to defend against the loop, e.g. by checking whether the objects' properties have changed. Even then the component will render twice because onBeforeUpdate runs after the initial update rendering.

I'm unclear why beforeMount and beforeUpdate have been moved to be after render. I haven't been able to find an RFC explaining why this change has been made. My guess would be it was for consistency with directive hooks. Or maybe something to do with SSR? Either way they seem less useful running after render.

@github-actions github-actions bot locked and limited conversation to collaborators Nov 6, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant