Почему Composable в Vue не изолирован?

Я использую Vue 3 с Nuxt 3 и Vite и столкнулся со странной ошибкой. Это происходит почти везде в моем приложении, когда я пытаюсь использовать useFetch внутри составного объекта.

Например, у меня есть следующая компоновка, позволяющая проверить, можно ли отобразить кнопку в зависимости от роли пользователя:

useCheckerRole Составной

export function useCheckerRole(policies){
  const {data, error} = await useFetch("/api/role-checker", {
    method: "POST",
    body: policies
  })

  if (data.value) {
    return data.value
  }

  if (error.value) {
    throw new Error("an error occured");
  }
}

Затем мне нужно будет передавать такие политики всякий раз, когда мне нужно будет проверить их роли.

const policies = await useCheckerRole([
  {
   component_ask: 'some-button',
   role_ask: 'administrator'
  }
])

который затем возвращает что-то вроде этого из API:

  [{
   component_ask: 'some-button',
   role_ask: 'administrator',
   status: 'approved'
  }]

Баг

Ошибка проявляется, когда я монтирую useCheckerRole в двух разных компонентах на одной странице.

Например, в моем компоненте верхней панели я использую useCheckerRole, чтобы определить, должна ли отображаться конкретная кнопка или меню, в зависимости от роли пользователя. Между тем, в другом месте страницы у меня есть еще одна кнопка, требующая аналогичной проверки на основе ролей.

TopBar.vue

Верхняя панель отправляет это в средство проверки ролей, а затем немедленно записывает результат.

const policies = await useCheckerRole([
  {
   component_ask: 'top-bar-button',
   role_ask: 'administrator'
  }
]).catch((error)....)

console.info("topBar Policies result", policies)

ChildPage.vue

Дочерняя страница отправляет это в useCheckerRole и немедленно регистрирует результат.

const policies = await useCheckerRole([
  {
   component_ask: 'child-page-button',
   role_ask: 'administrator'
  },
  {
   component_ask: 'child-page-other-button',
   role_ask: 'administrator'
  },
]).catch((error)....)

console.info("Child Policies result", policies)

TopBar.vue Результат

теперь результат Topbar выглядит интересно:

🐞 Что получил TopBar

[
  {
   component_ask: 'child-page-button',
   role_ask: 'administrator',
   status: "approved"
  },
  {
   component_ask: 'child-page-other-button',
   role_ask: 'administrator',
   status: "rejected"
  },
]

Обратите внимание, что это было не то, что компонент Topbar отправил в useCheckerRole, а то, что отправил ChildPage.

✅ Что должен был получить TopBar

[
  {
   component_ask: 'top-bar-button',
   role_ask: 'administrator',
   status: "approved"
  },
]

ChildPage также получил тот же результат, что и Topbar:

[
  {
   component_ask: 'child-page-button',
   role_ask: 'administrator',
   status: "approved"
  },
  {
   component_ask: 'child-page-other-button',
   role_ask: 'administrator',
   status: "rejected"
  },
]

Это заставило меня понять, что составные объекты не так изолированы, как я думал при использовании useFetch, или, возможно, я делаю что-то очень неправильно. Потому что похоже, что оба компонента одновременно вызывали одну и ту же неизолированную функцию, даже если указанная функция должна быть изолированной.

Первоначальный результат в TopBar был правильным. Однако когда ChildPage также вызвал ту же функцию, она каким-то образом переопределила результат, что, к сожалению, не было тем, что запрашивал TopBar.

Есть ли у кого-нибудь еще эта проблема?

Что такое версия Nuxt? Можно попробовать добавить cache: false к запросам. Более вероятно, что это API обеспечивает нежелательное кэширование POST-запросов, обычно этого не должно происходить.

Estus Flask 28.06.2024 10:39

@EstusFlask Эстус, спасибо, это помогло мне понять, в чем проблема. Я опубликую обновление. Большое спасибо. Я использую Nuxt 3.7.4, а также применил кеш: «no-cache» в опциях, вместо этого он воспроизвел для меня еще одну ошибку, но это помогло мне добраться туда, где мне нужно было отследить странный вывод. так что спасибо.

Egy Ramschie 01.07.2024 11:02
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
2
60
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Я думаю, это не из-за «изоляции», а из-за кэша useFetch. useFetch использует клавишу , чтобы предотвратить повторную выборку одних и тех же данных. По умолчанию key — это предоставленный URL-адрес, который одинаков в ваших двух компонентах. Можете ли вы попробовать назначить им другой ключ?

export function useCheckerRole(policies){
  const {data, error} = await useFetch("/api/role-checker", {
    method: "POST",
    body: policies,
    key: policies.component_ask
  })

  if (data.value) {
    return data.value
  }

  if (error.value) {
    throw new Error("an error occured");
  }
}

ОП предполагает, что это может быть как-то связано с кешированием, но я совершенно уверен, что Nuxt не использует кеш для POST по умолчанию, это было бы большой ошибкой с их стороны

Estus Flask 28.06.2024 09:48

@EstusFlask ах, вы правы, извините, я не заметил, что это POST, тогда нам может понадобиться минимальная репродукция для расследования.

Yue JIN 28.06.2024 10:00

@YueJIN, спасибо, ваш ответ очень приблизил меня к моей проблеме. каким-то образом благодаря этому мне удалось обнаружить странную проблему.

Egy Ramschie 01.07.2024 10:59
Ответ принят как подходящий

Поиграв направо и налево с решениями, которые дали Юэ Цзинь и Эстус Фласк, я наконец нашел проблему. Я наткнулся на эту статью — Nuxt 3 useFetch — правильно ли вы его используете? и прочитайте следующее высказывание автора:

Как правило, при использовании компонуемых объектов их следует вызывать только внутри; функция настройки, плагины и промежуточное программное обеспечение маршрута. Попытка использовать эту компоновку за пределами этой области приведет к ошибкам, которые повлияют на производительность приложения.

В статье он продемонстрировал, как возникла ошибка после упаковки useFetch в функцию. Сразу после этого я увидел, что моя функция действительно оборачивает составной объект, который оборачивает составной объект useFetch.

🐞Код, который приводит к ошибке

Компонент TopBar/ChildPage


<script setup>
const policy_list = ref([...])

async function checkRole(){
 const policies = await useCheckerRole(policy_list .value).catch((error)=> 
   {...}
 )
}

checkRole();

</script>

что useCheckerRole является составным элементом функции, использующей useFetch. Итак, странный баг действительно появился.

✅ Мое решение

lib/roleChecker.ts

Я решил проверить это, создав обычную функцию и поместив ее за пределы папки Composables; в папке с именем lib.

Внутри roleChecker.ts я больше не использую useFetch. Вместо этого я использую $fetch для вызова моего API и возврата их.

export default function roleChecker(
  url: string,
  options: { [key: string]: any },
  source?: string
) {
  return new Promise<any>(async (resolve, reject) => {
    console.info("roleChecker initialized");

    $fetch(url, options)
      .then((res) => {
        resolve(res);
      })
      .catch((error) => {
        reject(error);
      });
  });
}

Теперь для каждого моего компонента я наконец могу вызвать roleChecker внутри любой функции, и ошибки меня больше не беспокоят.

Топбар/дочерняя страница


<script setup>
import roleChecker from "/lib/roleChecker"
const policy_list = ref([...])

async function checkRole(){
 const policies = await roleChecker(policy_list .value).catch((error)=> 
   {...}
 )
}

checkRole();

</script>

Другие вопросы по теме