• vue3中customRef自定义ref(系列十)


    customRef
      返回一个ref对象,可以显式地控制依赖追踪和触发响应

    示例

    <template>
    <div>
      <p>{{obj}}</p>
      <button @click="inc">button</button>
    </div>
    </template>
    
    <script>
    import { customRef } from 'vue';
    
    // customRef用于 自定义ref
    // 自定义 ref 需要提供参数传值
    function myRef(value) {
        // 自定义 ref 需要提供 customerRef 返回值
        // customer 需要提供一个函数作为参数
        // 该函数默认带参数 track 和 trigger ,都是方法。
        return customRef((track, trigger) => {
          return {
            // customer 需要提供一个对象 作为返回值
            // 该对象需要包含 get 和 set 方法。
            get() {
              // track 方法放在 get 中,用于提示这个数据是需要追踪变化的
              track();
              console.log('get', value);
            
              return value;
            },
            // set 传入一个值作为新值,通常用于取代 value
            set(newValue) {
              console.log('set', newValue);
              value = newValue;
              // 记得触发事件 trigger,告诉vue触发页面更新
              trigger();
            }
          }
        })
    }
    
    export default {
      name: 'App',
      setup() {
        // let obj = ref(18); // reactive({value: 18})
    // 应用上面的自定义 ref ,使用方案和之前的 ref 是类似的。
        const obj = myRef(123);
        function inc() {
          obj.value += 1;
        }
    
        return {
          obj,
          inc
        };
      }
    }
    </script>

    这并不是一个多么复杂的方法,如果要使用,记得是在自定义的 ref 中返回一个 customRef,而 customRef 也要返回一个对象,相当于二重嵌套的返回。

    假如我们去掉了 track 和 trigger ,那么将失去视图层追踪变化的能力(可以显示控制)。如果需要进行视图层追踪,请注意在 set 中 value 发生变化后即刻执行 trigger

    #实例2

    考虑一个通常情况下会出现的场景,我们需要发送请求,获取数据,而这个过程是异步的。

    首先是数据,它放在 public 文件夹里。

    // data.json
    [
        {
            "name": "GuanYu",
            "id": 1
        },
        {
            "name": "ZhangFei",
            "id": 2
        },
        {
            "name": "MaChao",
            "id": 3
        },
        {
            "name": "ZhaoYun",
            "id": 4
        },
        {
            "name": "HuangZhong",
            "id": 5
        }
    ]
     

    如果我们并未使用 customRef 来执行自定义。fetch请求详情:阮一峰

    <template>
    <ul>
      <li v-for="item in obj" :key="item.id">
        {{item.id}} - {{item.name}}
      </li>
    </ul>
    </template>
    
    <script>
    import { ref } from 'vue';
    
    export default {
      name: 'App',
      setup() {
        // 创建一个空数组 ref
        const obj = ref([]);
        // 使用 fetch 异步获取文件内容
        fetch('../public/data.json')
          .then((res) => {
            return res.json();
          }).then((data) => {
            console.log(data);
            obj.value = data;
          }).catch((err) => {
            console.log(err);
          })
    
        return {
          obj,
        };
      }
    }
    </script>

    此时在setup函数中(setup函数: 只能是一个同步的函数, 不能是一个异步的函数,如async setup),有多个异步回调函数,不美观,是否可用同步效果呢,可以采用自定义ref实现

    这是一个办法,但还有更加具有可复用性的方案。

    <template>
    <ul>
      <li v-for="item in obj" :key="item.id">
        {{item.id}} - {{item.name}}
      </li>
      <button @click="getNewObj">newObj</button>
    </ul>
    </template>
    
    <script>
    import { customRef } from 'vue';
    
    function fetchRef(value) {
      return customRef((track, trigger) => {
        // 用于存储获得的数据
        let ans;
        function getAns() {
          fetch(value)
            .then((res) => {
              return res.json();
            }).then((data) => {
              console.log(data);
              // 将获得的数据存储起来
              ans = data;
              // 提示触发视图层变化
              trigger();
            }).catch((err) => {
              console.log(err);
            });
        }
        getAns();
        return {
          get() {
            track();  //告诉vue这个数据需要追踪变化
            return ans;
          },
          set(newValue) {
            value = newValue;
            // 修改 value 的同时再次进行数据的抓取
            getAns();
          }
        }
      })
    }
    
    export default {
      name: 'App',
      setup() {
        const obj = fetchRef('../public/data.json');
    
        // 修改数据源
        function getNewObj() {
          obj.value = '../public/data1.json';
        }
        return {
          obj,
          getNewObj
        };
      }
    }
    </script>
     // 注意点:
            // 不能在get方法中发送网络请求,会循环发送请求
            // 渲染界面 -> 调用get -> 发送网络请求
            // 保存数据 -> 更新界面 -> 调用get
     

    在这个方案中,我将 获取数据的方案 封装存储在 自定义ref 中,在初始化的时候,调用get函数,发送请求,会在获取数据之后,在更新页面之前,执行 trigger 进行视图层的变化

    而在设置新值的时候,再次触发获取数据的方案,从而实现复杂的双向数据绑定。在setup函数就实现一个同步代码方式,美观

    点击 button ,可以改变数据,并实现视图层的变化。

    // data1.json
    [
        {
            "name": "LiuBei",
            "id": 6
        },
        {
            "name": "CaoCao",
            "id": 7
        },
        {
            "name": "SunQuan",
            "id": 8
        }
    ]
  • 相关阅读:
    玛利亚∙多斯普拉泽雷斯
    八月惊魂
    电话
    占梦人
    睡美人
    [可并堆] Bzoj P4585 烟火表演
    [三分套三分] Codeforces NEERC 13 E. Easy Geometry
    [可并堆] Bzoj P1367 sequence
    [dp][组合数] Jzoj P6303 演员
    [树形dp][Tarjan][单调队列] Bzoj 1023 cactus仙人掌图
  • 原文地址:https://www.cnblogs.com/fsg6/p/14485972.html
Copyright © 2020-2023  润新知