New data responsive first experience

<div id="app"> <h3>{{state.title}}</h3> <p>counter: {{state2.counter}}</p> </div> <script src="https://unpkg.com/vue@next"></script> <script> const { createApp, reactive, Function useTitle() {const state = reactive({title: 'hello vue3!!!!! ' }) onMounted(() => { state.title = 'vue3, hello!!! ' }) setTimeout(() => { state.title = 'title 2s' }, 2000); return state } function useCounter() { const state2 = reactive({ counter: 0 }) onMounted(() => { state2.counter = 1 }) return state2 } const app = createApp({ setup() { // title const state = UseTitle () // counter const state2 = useCounter() // context render with return {state, state2}}, }) app.mount('#app') </script>Copy the code

Data responsive innovation

  1. Initialization is recursive and slow
  2. Dependencies occupy a lot of resources
  3. Array support requires special implementation
  4. Adding dynamically, removing attributes requires additional API
  5. Map and Set are not supported

Handwritten data responsive implementation

  1. Proxy-based data responsiveness
  • reactive()
    Copy the code
  1. Depend on the collection
  • Add side effect()
  • Rely on collect track()
  • Trigger side effect trigger()

< div id = "app" > < h3 > {{title}} < / h3 > < / div > < script > / / receiving obj, agent for it, DefineProperty () function reactive(obj) {// vue3 based on Proxy return new Proxy(obj, {get(target, key) { console.log('get', key); Track (target, key) return target[key]}, set(target, key, val) {console.log('set', key); track(target, key) return target[key]}, set(target, key, val) {console.log('set', key); Target [key] = val // update() // app.update() // trigger dependent trigger(target, key)} Const effectStack = [] function effect(fn) {const effectStack = [] function effect(fn) { Const eff = function () {try {effectstack.push (eff) fn()} finally {effectStack.pop()}} Eff () return eff} track () {target: {key: [eff]}} const targetMap = {} function track(target, Const effect = effectStack[effectstack.length-1] if (effect) {let map = targetMap[target] if (! map) { map = targetMap[target] = {} } let deps = map[key] if (! Deps) {deps = map[key] = []} // Put side effects into deps if (deps.indexof (effect) === -1) {deps.push(effect)}} function trigger(target, key) { const map = targetMap[target] if (map) { const deps = map[key] if(deps) { deps.forEach(dep => dep()) } } } // CreateApp returns what the application instance looks like const Vue = {createApp(options) {// Exposed to the browser platform const renderer = Vue. CreateRenderer ({ querySelector(selector) { return document.querySelector(selector) }, insert(child, parent, anchor) { parent.insertBefore(child, anchor || null) } }) return renderer.createApp(options) }, createRenderer({ querySelector, Return {createApp(options) {return {mount(selector) {// What is the target of the mount? Const parent = querySelector(selector) const parent = querySelector(selector) Options.render) {options.render = this.compile(parent.innerhtml)} // Compatible options API if (options.setup) {// SetupState = options.setup()} else {this.data = options.data()} // Proxy // determine where to fetch data in render this.proxy = new Proxy(this, { get(target, key) { if (key in target.setupState) { return target.setupState[key] } else { return target.data[key] } }, set(target, key, val) { if (key in target.setupState) { target.setupState[key] = val } else { target.data[key] = val } } }) // This.update = effect(() => {const el = options.render. Call (this.proxy) // appends to the host element AppendChild (el) insert(el, parent)}) // Initialize this.update()}, Template return function render() {const h3 = document.createElement('h3') h3.textContent = this.title return h3 } } } } } } } </script> <script> const { createApp } = Vue const app = createApp({ setup() { // // Avoid this const state = reactive({title: 'hello vue3!!!!!! ' }) setTimeout(() => { state.title = 'vue3, hello!!!!!! '}, 2000); return state }, }) app.mount('#app') </script>Copy the code