Are methods in Vue reactive?

前端 未结 3 1837
后悔当初
后悔当初 2021-01-02 01:38

I\'ve been using Vue for a while, and my experience has always been a method will recompute if its underlying reactive data is updated. I\'ve encountered conflicting informa

相关标签:
3条回答
  • 2021-01-02 02:01

    This is a very interesting case.

    From what I have read and my experience I can say that: No, methods are not inherently reactive. A method must be explicitly called for it to execute.

    But, then how can I explain your case? I put your code in in a sandbox and sure enough, as you push id's into the array, the template updates to display the animal name. This would indicate some reactivity. What gives?

    Well, I ran an experiment. I added a simple div to each loop that generates a random number when generated.

    <li v-for="animal in animals" :key="animal.id">
            <div>{{ random() }}</div>
            <span v-if="isAwesome(animal)">{{ animal.name }}</span>
    </li>
    
    ...
    
    random() {
          return Math.random();
    }
    

    And what I saw was that every time a new id was pushed into the array, all the random numbers would change. This is the key to understand why it "seems" as though the method isAwesome is reactive.

    Somehow, when a new ID is pushed to the array, Vue re-renders the loop entirely, hence executing the methods again. I can't explain the inner workings of why vue re-renders the entire loop, that would require further research.

    So to answer your question. isAwesome is not reactive, it is merely an illusion created by the re-render of the loop.

    0 讨论(0)
  • 2021-01-02 02:05

    Based on How Changes Are Tracked from the docs, here's what's going on:

    1. A special watcher is created for the component instance to determine when a re-render is required.

    2. Vue converts all properties of data to getters and setters.

    get animals() {
      // Add dependency: potentially trigger a re-render if animals updates
      ...
    }
    set animals() {
      // Notify the watcher that animals has been updated
      ...
    }
    get awesomeAnimalIds() {
      // Add dependency: potentially trigger a re-render if awesomeAnimalIds updates
      ...
    }
    set awesomeAnimalIds() {
      // Notify the watcher that awesomeAnimalIds has been updated
      ...
    }
    
    
    1. The template is rendered. During the render, a call to isAwesome is made from the template.
    2. In the body of isAwesome, the getter for awesomeAnimalIds is invoked.
    3. The watcher establishes a dependency on the awesomeAnimalIds field of data.
    4. After a timeout, awesomeAnimalIds is updated, which invokes the awesomeAnimalIds setter.
    5. Because the template depends on a data field which received a notification, a re-render is triggered.
    6. Repeat step (3).

    From this and this example above, we can conclude the following:

    A method call made from a template establishes a reactive dependency on the subset of data fields used in the method call stack. If the underlying fields are updated, it will trigger a re-render of the component.

    There is a common misconception that methods are "invoked only once" or "fire and forget" when called from a template. This is clearly not always the case because methods can establish a reactive dependency.

    So when should we use a computed property vs a method?

    See the guide section on Computed Caching vs Methods. Here's my take on it:

    • A computed property will only reevaluate when its reactive dependencies have changed. I.e. it uses caching for improved efficiency.
    • Computed properties should be side-effect free. E.g. you shouldn't call fetch from them.
    • Always prefer a computed property to a method if possible for efficiency reasons.
    • Use a method if you have side effects or if you need to pass in an argument (as seen in the original question).
    0 讨论(0)
  • 2021-01-02 02:06

    No, methods are not reactive. Only data can be reactive in Vue.

    BUT its is important understand how Vue works...

    1. Vue will take your template, compiles it into render function and runs the render function
    2. While the render function is running, Vue monitors all data() members (it does this all the time, not only during 1st render). If any of the data is accessed during render, Vue knows that content of this data member influences the result of rendering.
    3. Vue use the knowledge gathered in step 2. Whenever data member "touched" during rendering changes, it knows re-render should happen and do the thing...

    It doesn't matter if you reference the data member directly, use it in computed or in a method. If the data is "touched" during rendering, the change of the data will trigger re-render in the future...

    0 讨论(0)
提交回复
热议问题