[Vue3] responsiveness data

reactive & ref

reactive method

  • Receive the parameter value and return a responsive Proxy object, that is, a responsive copy of the parameter value
  • Parameter value: reference type data
  • Advantages: even if only part of the data of the reference type is modified, eg: the data of the page will change when a property of the object / an item of the array is modified
    In Vue2, for reference type data, the proxy is the data itself. The data of the page will change only when the whole data needs to be modified
  1. Introducing reactive methods:
    import { reactive } from "@vue/reactivity"; / import { reactive } from "vue";
  2. Format: reactive (responsive data)
  3. Return value: Proxy object, which is the Proxy of parameter value (note that it is the object returned)
  4. Data acquisition: direct acquisition
<template>
    <p>arr: {{ arr }}</p>
    <button @click="changeData">Modify data</button>
</template>

<script>
import { reactive } from "@vue/reactivity";
export default {
    name: "App",
    setup() {
        let arr = reactive(["a", "b", "c"]);
        function changeData() {
            console.log("arr", arr);
            arr[1] = "e"; // Get and modify element data directly
        }
        return { arr, changeData };
    },
};
</script>

ref method

  • Accept the parameter value and return a responsive ref object. There is only one ref object Value attribute, pointing to the parameter value
  • Parameter value: reference type data and basic type data
    • For reference type data, it is actually processed by the reactive method and returns a Proxy object
    • For basic type data, use object Defineproerty() cooperates with get and set to obtain and modify data
  1. Introducing ref method:
    import { ref } from "@vue/reactivity"; / import { ref } from "vue";
  2. Format: ref (responsive data)
  3. Return value: RefImpl object (note that the object is returned)
  4. Get data: return value value
<template>
    <p>name: {{ name }}</p>
    <p>arr: {{ arr }}</p>
    <button @click="changeData">Modify data</button>
</template>

<script>
import { ref } from "@vue/reactivity";
export default {
    name: "App",
    setup() {
        let name = ref("superman");
        let arr = ref(["a", "b", "c"]);
        function changeData() {
            console.log("name", name.value); // superman
            name.value = "superwoman";
            console.log("arr", arr.value); // Proxy
            arr.value[1] = "e";
        }
        return { name, arr, changeData };
    },
};
</script>

shallowReactive & shallowRef

shallowReactive

  • For the object data decorated with shallowReactive, only the layer 1 attribute is responsive
  • Note: when modifying the attribute value, the page does not respond, but the data has been changed
    If the page is re rendered, the latest data will still be displayed
<template>
    <p>obj.name: {{ obj.name }}</p>
    <button @click="obj.name += '!'">modify name</button>
    <p>obj.girlfriend.name: {{ obj.girlfriend.name }}</p>
    <button @click="obj.girlfriend.name += '!'">
        modify obj.girlfriend.name
    </button>
</template>

<script>
import { shallowReactive } from "@vue/reactivity";
export default {
    name: "App",
    setup() {
        let obj = shallowReactive({
            name: "superman",
            // Deep data is not responsive
            girlfriend: {
                name: "superwoman",
            },
        });
        return {
            obj,
        };
    },
};
</script>

shallowRef

  • For the data modified by shallowRef, only the data itself is responsive, and its attributes are not responsive
  • Note: when modifying the attribute value, the page does not respond, but the data has been changed
    If the page is re rendered, the latest data will still be displayed
<template>
    <p>obj.name: {{ obj.name }}</p>
    <!-- Modify the property, no response -->
    <button @click="obj.name += '!'">modify obj.name</button> |
    <!-- Modify the object itself to respond -->
    <button @click="obj = newObj">modify obj</button>
    <hr />
    <p>gender: {{ gender }}</p>
    <!-- Modify the data itself to respond -->
    <button @click="gender += '!'">modify gender</button>
</template>

<script>
import { shallowRef } from "@vue/reactivity";
export default {
    name: "App",
    setup() {
        let obj = shallowRef({
            name: "superman",
        });
        let newObj = {
            name: "superwoman",
        };
        let gender = shallowRef("male");
        return { obj, gender, newObj };
    },
};
</script>

Here, we first change the attribute value of the object to find that the page has not been updated; Then we change the basic type data. We can find that the basic type data and the attribute values of the previously modified objects are updated
This is because: the attribute value of the object is modified. Although the page is not updated, the data has been changed. If the page is re rendered, the latest data will still be displayed

toRef & toRefs

  • Format: toref (responsive data object, "object data attribute name")
  • Function: provide an attribute in the responsive object to external users separately to facilitate data acquisition
<template>
    <p>name: {{ name }}</p>
    <button @click="name += '!'">modify name</button>
    <p>girlfriendName: {{ girlfriendName }}</p>
    <button @click="girlfriendName += '!'">modify girlfriendName</button>
</template>

<script>
import { reactive, toRef } from "@vue/reactivity";
export default {
    name: "App",
    setup() {
        let obj = reactive({
            name: "superman",
            girlfriend: {
                name: "superwoman",
            },
        });
        // Set the corresponding variable here in return
        return {
            obj,
            // Using the toRef method
            name: toRef(obj, "name"),
            girlfriendName: toRef(obj.girlfriend, "name"),
        };
    },
};
</script>
  • At this time, the newly created variable will be associated with the original data. If the variable changes, the original data will also change

toRefs

  • It is used to separate all attributes of object data
  • Format: Torefs (object data)
  • Note: only layer 1 attribute data can be parsed here
<template>
    <p>name: {{ name }}</p>
    <button @click="name += '!'">modify name</button>
    <!-- Note: only layer 1 data can be parsed here -->
    <p>girlfriend.name: {{ girlfriend.name }}</p>
    <button @click="girlfriend.name += '!'">modify girlfriend.name</button>
</template>

<script>
import { reactive, toRefs } from "@vue/reactivity";
export default {
    name: "App",
    setup() {
        let obj = reactive({
            name: "superman",
            girlfriend: {
                name: "superwoman",
            },
        });
        // Use torefs (object data)
        let { name, girlfriend } = toRefs(obj);
        return { name, girlfriend };
    },
};
</script>

customRef

  • Method for customizing ref: customRef(callback)
  • callback receives two function parameters: track - for tracking data updates and trigger - for re rendering pages
  • callback returns an object with getter and setter methods
  • The getter method needs to set the return value, which is the data displayed on the page

Normal use ref:

<template>
    <p>App: {{ msg }}</p>
    <input type="text" v-model="msg" />
</template>

<script>
import { ref } from "@vue/reactivity";
export default {
    name: "App",
    setup() {
        let msg = ref("superman");
        return { msg };
    },
};
</script>

Custom ref

<template>
    <p>{{ personName }}</p>
    <input type="text" v-model="personName" />
</template>

<script>
import { customRef } from "vue";
export default {
    name: "App",
    setup() {
        function myRef(value) {
            // Use customRef to customize the ref method
            return customRef((track, trigger) => {
                // The callback function receives parameters: track and trigger
                // The callback function returns an object
                return {
                    // Set getter method
                    get() {
                        console.log("getValue", value);
                        // Call track to track data changes
                        track();
                        // Returns the displayed data
                        return value;
                    },
                    // Set setter method
                    set(newValue) {
                        console.log("setValue", value);
                        console.log("newValue", newValue);
                        value = newValue;
                        // Call the trigger method and let the vue template update the data
                        trigger();
                    },
                };
            });
        }
        let personName = myRef("superman");
        return { personName };
    },
};
</script>

In the above example, the page uses the personName data twice, so the getValue value value will be output twice during rendering

  • We can add the required functions in the custom ref method: eg we need to modify the data for 1s before rendering the page
<template>
    <p>{{ personName }}</p>
    <input type="text" v-model="personName" />
</template>

<script>
import { customRef } from "vue";
export default {
    name: "App",
    setup() {
        function myRef(value) {
            let trim = null; // Define variables for anti shake
            return customRef((track, trigger) => {
                return {
                    get() {
                        track();
                        return value;
                    },
                    set(newValue) {
                        // clearTimeout before use
                        clearTimeout(trim);
                        trim = setTimeout(() => {
                            value = newValue;
                            trigger();
                        }, 1000);
                    },
                };
            });
        }
        let personName = myRef("superman");
        return { personName };
    },
};
</script>

readonly & shallowReadonly

  • The data modified by readonly cannot be modified
<template>
    <p>obj.name: {{ obj.name }}</p>
    <button @click="obj.name += '!'">modify obj.name</button>
    <hr />
    <p>reObj.name: {{ reObj.name }}</p>
    <!-- Click will not be modified, and the console will throw a warning -->
    <button @click="reObj.name += '!'">modify reObj.name</button>
</template>

<script>
import { reactive, readonly } from "@vue/reactivity";
export default {
    name: "App",
    setup() {
        let obj = reactive({
            name: "superman",
        });
        let reObj = readonly(obj);
        return { obj, reObj };
    },
};
</script>

shallowReadonly

  • shallowReadonly modified data. Shallow data cannot be modified, but deep data can be modified
<template>
    <!-- Shallow data -->
    <p>obj.name: {{ obj.name }}</p>
    <button @click="obj.name += '!'">modify obj.name</button>
    <p>reObj.name: {{ reObj.name }}</p>
    <!-- Click will not be modified, and the console will throw a warning -->
    <button @click="reObj.name += '!'">modify reObj.name</button>
    <hr />
    <!-- Deep data -->
    <p>obj.girlfriend.name: {{ obj.girlfriend.name }}</p>
    <button @click="obj.girlfriend.name += '!'">
        modify obj.girlfriend.name
    </button>
    <p>reObj.girlfriend.name: {{ reObj.girlfriend.name }}</p>
    <!-- Click to modify -->
    <button @click="reObj.girlfriend.name += '!'">
        modify reObj.girlfriend.name
    </button>
</template>

<script>
import { reactive, shallowReadonly } from "@vue/reactivity";
export default {
    name: "App",
    setup() {
        let obj = reactive({
            name: "superman",
            girlfriend: {
                name: "superwoman",
            },
        });
        let reObj = shallowReadonly(obj);
        return { obj, reObj };
    },
};
</script>

toRaw

  • Change reactive data into normal data: toraw
<template>
    <p>obj.name: {{ obj.name }}</p>
    <button @click="obj.name += '!'">modify obj.name</button>
    <hr />
    <p>raObj.name: {{ raObj.name }}</p>
    <button @click="raObj.name += '!'">modify raObj.name</button>
</template>

<script>
import { reactive, toRaw } from "@vue/reactivity";
export default {
    name: "App",
    setup() {
        let obj = reactive({
            name: "superman",
        });
        let raObj = toRaw(obj);
        return { obj, raObj };
    },
};
</script>

The page will be modified to normal data, and the data will be re rendered
However, the data has been changed. If the page is re rendered, the latest data will still be displayed

markRaw

  • Used to mark an object data so that it can never become a responsive data
<template>
    <p>obj: {{ obj }}</p>
    <p>
        Step 1: select to receive data
        <button @click="changeObj">changeObj</button> |
        <button @click="maChangeObj">maChangeObj</button>
    </p>
    <p>
        Step 2: select the changed data
        <button @click="changeName">changeName</button> |
        <button @click="changeGirl">changeGirl</button>
    </p>
</template>

<script>
import { markRaw, reactive } from "@vue/reactivity";
export default {
    name: "App",
    setup() {
        // Define responsive data
        let obj = reactive({
            name: "superman",
        });

        // Suppose you receive an object data via Ajax
        function changeObj() {
            let girl = { name: "superwoman" };
            obj.girlfriend = girl;
        }

        // Suppose you receive an object data through Ajax and decorate it with markRaw
        function maChangeObj() {
            let girl = markRaw({ name: "superwoman" });
            obj.girlfriend = girl;
        }

        // Change received data
        function changeGirl() {
            obj.girlfriend.name += "!";
        }

        // Change original data
        function changeName() {
            obj.name += "!";
        }

        return {
            obj,
            changeObj,
            changeGirl,
            maChangeObj,
            changeName,
        };
    },
};
</script>

It can be found that the normally received object data can be modified and rendered on the page; However, for the object data decorated with markRaw, the data will be modified, but will not be rendered to the page (of course, the latest data will still be displayed when the page is re rendered)

Keywords: Javascript Front-end Vue Vue.js

Added by carlmcdade on Tue, 15 Feb 2022 14:31:31 +0200