Реэкспорт загрузчиков

routeAction$ и routeLoader$ обычно объявляются в файлах маршрута, таких как layout.tsx, index.tsx и plugin.tsx в директории routes (документация).

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

Решение

Вы можете определить routeAction$ и routeLoader$ в своем пользовательском пути и реэкспортировать их в ваших файлах layout.tsx, index.tsx и plugin.tsx.

Пример многократно используемой логики

Представим, что у нас есть routeLoader$, который проверяет, вошёл ли пользователь в систему или нет. Не имеет смысла копировать и вставлять один и тот же код в разные части нашего кода. Согласно хорошим практикам, идеальным способом является централизация логики. В этом примере мы объявляем routeAction$ и routeLoader$ в централизованном файле, чтобы затем повторно использовать их в других файлах.

Пример с ./shared/loaders.ts

import { routeAction$, routeLoader$ } from '@builder.io/qwik-city';
 
export const useCommonRouteAction = routeAction$(async () => {
  // ...
  return { success: true, data: ['Qwik', 'Partytown'] };
});
 
export const useCommonRouteLoader = routeLoader$(async () => {
  // ...
  return ['Mitosis', 'Builder.io'];
});

Теперь вы можете использовать ваши общие routeAction$ и routeLoader$ в путях, подобных этому ./src/routes/index.tsx.

import { component$ } from '@builder.io/qwik';
import { Form } from '@builder.io/qwik-city';
import { useCommonRouteAction, useCommonRouteLoader } from './shared/loaders';
 
// Как уже говорилось, здесь мы реэкспортируем их
export { useCommonRouteAction, useCommonRouteLoader } from './shared/loaders';
 
export default component$(() => {
  const commonRouteAction = useCommonRouteAction();
  const commonRouteLoader = useCommonRouteLoader();
 
  return (
    <div class="flex justify-around text-xl">
      <Form action={commonRouteAction}>
        <div class="mb-2">CommonRouteAction</div>
        <div class="mb-4">ответ:</div>
        <div class="text-lg font-bold mb-4">
          {commonRouteAction.value?.data.join(' ') || ''}
        </div>
        <button type="submit">Отправить</button>
      </Form>
      <div>
        <div class="mb-2">CommonRouteLoader</div>
        <div class="mb-4">ответ:</div>
        <div class="text-lg font-bold mb-4">{commonRouteLoader.value.join(' ')}</div>
      </div>
    </div>
  );
});

Пример с библиотекой сторонних разработчиков

Может случиться так, что нам понадобится интегрировать сторонние библиотеки, работу которых мы не контролируем. Давайте подумаем, например, об интеграции метода оплаты в наше приложение. Нам предоставляется компонент для интеграции в страницу, но мы не имеем никакого контроля над тем, что происходит под капотом этого компонента. Итак, если этой библиотеке нужны routeAction$ или routeLoader$, мы должны реэкспортировать их, чтобы обеспечить корректную работу нашей библиотеки.

Вот наш код:

import { component$ } from '@builder.io/qwik';
import { ThirdPartyPaymentComponent } from './third-party-library';
 
// Как уже говорилось, здесь мы реэкспортируем сторонний загрузчик
export { useThirdPartyPaymentLoader } from './third-party-library';
 
export default component$(() => {
  return (
    <section>
      <ThirdPartyPaymentComponent />
    </section>
  );
});

Здесь представлен код библиотеки:

import { component$ } from '@builder.io/qwik';
import { routeLoader$ } from '@builder.io/qwik-city';
 
export const useThirdPartyPaymentLoader = routeLoader$(() => {
  return { name: 'John Doe' };
});
 
export const ThirdPartyPaymentComponent = component$(() => {
  const thirdPartyPaymentLoader = useThirdPartyPaymentLoader();
  return (
    <div
      class={[
        'w-96 h-56 m-auto rounded-xl relative text-white font-bold shadow-2xl',
        'transition-transform transform hover:scale-110 bg-gray-600',
      ]}
    >
      <div class="w-full px-8 absolute top-8">
        <div class="flex justify-between">
          <div class="">
            <p>Name</p>
            <p class="tracking-widest">{thirdPartyPaymentLoader.value.name}</p>
          </div>
          <img class="w-12 h-12" src="/logos/qwik-logo.svg" />
        </div>
        <div class="pt-1">
          <p class="font-medium">Номер карты</p>
          <p class="tracking-wider">4642 3489 9867 7632</p>
        </div>
        <div class="pt-6 pr-6">
          <div class="flex justify-between text-xs">
            <div>
              <p class="font-medium">Действует с</p>
              <p class="tracking-wider">11/15</p>
            </div>
            <div>
              <p class="font-medium">Срок действия</p>
              <p class="tracking-wider">03/25</p>
            </div>
            <div>
              <p class="font-medium">CVV</p>
              <p class="tracking-wider">···</p>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
});

Участники

Спасибо всем участникам, которые помогли сделать эту документацию лучше!

  • gioboa
  • aendel