onStop

In the last section, we completed the logic related to stop, stop(runner) can avoid the automatic execution of runner function when responsive data changes, now there is a new requirement, I want to do some processing when stop execution, how to implement this?

A single measurement

Let’s read the single test below

// src/reactivity/test/effect.spec.ts
describe("effect".() = >{... it("onStop".() = > {
    // Create the responsive object obj
    const obj = reactive({
      foo: 1
    })
    const onStop = jest.fn() // define a jest function
    let dummy
    // Effect returns runner with an onStop callback defined in the second argument
    const runner = effect(() = > {
      dummy = obj.foo
    }, {
      onStop
    })
    // Expect the onStop callback to be executed after stop is executed
    stop(runner)
    expect(onStop).toBeCalledTimes(1)})})Copy the code

According to the description of the single test above, in fact, this function is very simple, that is, when executing stop, effect will be passed in the onStop function.

coding

From the above test case, the use of onStop is very similar to scheduler in that it is passed through the second argument to Effect

1. Receiving and transmittingonStop

First, we find the effect function, get the onStop argument from options, and assign it to the instantiation object _effect.

// src/reactivity/effect.ts
export function effect (fn, options:any = {}) {... _effect.onStop = options.onStop ... }Copy the code

? > < p style = “max-width: 100%; clear: both; min-height: 1em; Since the stop method we wrote about in the previous section actually calls a ReactiveEffect class, we assign onStop to the instantiation object as well, making it easier to call from inside stop.

2, callonStopmethods

In the previous step, we passed the onStop method we received to the instantiation object _effect. Next, we need to define an onStop in ReactiveEffect and call it when stopped

// src/reactivity/effect.ts

class ReactiveEffect {
  ...
  onStop?: () = > void  //onStop is optional. stop () {if (this.active) {
      cleanupEffect(this)
      // When onStop is received, execute it
      if (this.onStop) {
        this.onStop()
      }
      this.active = false}}}Copy the code

At this point, that’s all the onStop logic

Optimization scheme

_effect.onStop = options.onStop. In effect, we assign the value of the second parameter to effect one by one. Every time I do this, it’s a little tedious, so let’s optimize this code.

? > < span style = “max-width: 100%; clear: both; min-height: 1em;

We can do this using object.assign.

// src/shared/index.ts
export const extend = Object.assign

Copy the code
import {extend} from '.. /shared'
export function effect (fn, options:any = {}) {... extend(_effect, options) ... }Copy the code

Above, we not only simplified the code here by creating a shared public library and then referring to it in effect to assign objects, but also freed up a common function that can be called elsewhere later.

The test results

PS D:\user\desktop\mini-vue> yarn testYarn run v1.22.10 $jest PASS SRC/reactivity/tests/reactive spec. Ts PASS/SRC/reactivity tests/index. The spec. Ts PASS src/reactivity/tests/effect.spec.ts Test Suites: 3 passed, 3 total Tests: 7 passed, 7 total Snapshots: 0 total Time: 1.848 s Ran alltest suites.
Done in4.11 s.Copy the code

conclusion

When writing onStop, we refer to the scheduler method, assign value in effect first, then define an onStop in ReactiveEffect and call it in stop, not only that, we also remove the public method from the code to simplify the code logic. More to achieve the reuse of code.

In the next section, learn about readOnly!