javascript 如何将一个Vue引用重新分配给另一个引用并保持React性?

pjngdqdw  于 2023-05-27  发布在  Java
关注(0)|答案(1)|浏览(149)

我的Vue组件看起来像这样(简化):

<template>
  <div @click="loadEvents">{{ loading }}</div>
</template>

<script setup>
import { ref } from 'vue'
let loading = ref(false)

loadEvents()
function loadEvents() {
  const res = backendApi.getEvents(selectedDate.value)
  loading = ref(res.loading)
}
</script>

方法“backendApi.getEvents”看起来像这样:

getEvents() {
  const loading = ref(true)
  axios.get(...).then(r => loading.value = false)
  
  return { loading }
}

问题是,在初始页面加载加载正确显示在网站上,第一个“真”,然后“假”后,请求已经完成。但是当通过点击div再次触发“loadEvents”函数时,“loading”值仍然保持为“false”,并且在DOM中不会更新。我做错了什么,我该如何解决?我试过做loading.value = res.loading.value,但这只会将“loading”更改为“true”,而在请求完成后,它不会更改为“false”。

mwg9r5ms

mwg9r5ms1#

一个简短的回答是:
不能重新分配React对象,因为旧的引用将指向前一个对象值,React性将丢失。所有React变量都应该用const声明。
但你似乎把逻辑复杂化了。正如我所理解的,当axios加载数据时,loading应该为true(只要正确导入即可):

<template>
  <div @click="loadEvents">{{ loading }}</div>
</template>

<script setup>

const loading = ref(false);

loadEvents()

async function loadEvents() {
  loading.value = true;
  const results = await backendApi.getEvents(selectedDate.value);
  // use results here
  // ...
  loading.value = false;
}

function getEvents() {
  return axios.get(...);
}

</script>

但是你可以改进它,并重用loading,将其移动到后端API:

// your backend-api.js:

export const loading = ref(false);

export const backendApi = {
  getEvents(){
    return this.callApi(...);
  },
  async callApi(...args){
    loading.value = true;
    const result = await axios.get(...args);
    loading.value = false;
    return result;
  }
};

// your component
<template>
  <div @click="loadEvents">{{ loading }}</div>
</template>

<script setup>

import {loading, backendApi} from './backend-api.js';

loadEvents()

async function loadEvents() {
  const results = await backendApi.getEvents(selectedDate.value);
  // use results here
  // ...
}

</script>

更新

经过与作者的讨论,有一些新的解决方案。
作者指出,每个后端调用都需要一个加载引用。把加载移到后端API不是很好,我们需要一些api调用的 Package 等等。整个逻辑变得不可知论,这看起来并不完美。所以...
最近,我已经成为一个球迷的一个setter与一些行动和承诺setters是我的新宠。通常我有一些模块带有我的Vue utils,所以在这个例子中,我创建了promiseRef(),它返回一个带有额外的'promise'属性的boolean ref,该属性控制它的false/true值。这样我们就有了独立于任何其他逻辑的加载引用,包括一些后端API作为不必要的依赖。所以整个设置看起来像这样:

<script setup>
    
  import { backendApi } from './backend-api.js';
  import { promiseRef } from './utils.js'
  
  const loading = promiseRef();

  async function loadEvents(){
     const result = await (loading.promise = backendApi.getEvents());
    // use your results
  }

</script>

<template>
  <button @click="loadEvents">{{ loading }}</button>
</template>

backend-api.js:

// just emulating some api call
export const backendApi = {
  getEvents(){
    return new Promise(resolve => setTimeout(resolve, 2000));
  }  
}

utils.js:

import { ref } from 'vue';
export const promiseRef = value => {
  
  const loading = ref(value || false);
  
  let promise;
  
  Object.defineProperty(loading, 'promise', {
    get(){
      return promise;
    },
    set(val){
      loading.value = true;
      (promise = val).then(() => loading.value = false);
    }
  });
  
  return loading;
  
};

一个工作的Vue 3要点在这里!

相关问题