Интеграция Directus с фронтендом (React/Vue/Next.js)

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Предлагаемые услуги
Показано 1 из 1 услугВсе 2065 услуг
Интеграция Directus с фронтендом (React/Vue/Next.js)
Средняя
~3-5 рабочих дней
Часто задаваемые вопросы

Наши компетенции:

Этапы разработки

Последние работы

  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    874
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    851

Интеграция Directus с фронтендом (React/Vue/Next.js)

Directus предоставляет официальный TypeScript SDK с типизированными запросами. Для Next.js App Router — Server Components для серверных запросов и React hooks для клиентского взаимодействия.

Установка SDK

npm install @directus/sdk

Настройка клиента

// lib/directus.ts
import { createDirectus, rest, staticToken, readItems, readItem, readSingleton } from '@directus/sdk'

// Типы для коллекций
interface Article {
  id: number
  title: string
  slug: string
  content: string
  excerpt: string
  status: 'draft' | 'published' | 'archived'
  date_published: string
  thumbnail: { id: string; filename_disk: string } | null
  category: { id: number; name: string; slug: string } | null
  author: { id: string; first_name: string; last_name: string } | null
}

interface DirectusSchema {
  articles: Article[]
  categories: { id: number; name: string; slug: string }[]
  products: { id: number; name: string; price: number; stock: number }[]
}

const directus = createDirectus<DirectusSchema>(process.env.DIRECTUS_URL!)
  .with(staticToken(process.env.DIRECTUS_STATIC_TOKEN!))
  .with(rest())

export { directus }

// Вспомогательная функция для URL медиа
export function getDirectusAssetURL(fileId: string, params?: Record<string, string>) {
  const url = new URL(`/assets/${fileId}`, process.env.DIRECTUS_URL)
  if (params) {
    Object.entries(params).forEach(([key, value]) => url.searchParams.set(key, value))
  }
  return url.toString()
}

Server Components (Next.js App Router)

// app/articles/page.tsx
import { directus } from '@/lib/directus'
import { readItems } from '@directus/sdk'

export default async function ArticlesPage({
  searchParams,
}: {
  searchParams: { page?: string; category?: string }
}) {
  const page = Number(searchParams.page) || 1
  const limit = 12

  const articles = await directus.request(
    readItems('articles', {
      fields: ['id', 'title', 'slug', 'excerpt', 'date_published',
        { thumbnail: ['id', 'filename_disk', 'width', 'height'] },
        { category: ['name', 'slug'] },
      ],
      filter: {
        status: { _eq: 'published' },
        ...(searchParams.category ? { category: { slug: { _eq: searchParams.category } } } : {}),
      },
      sort: ['-date_published'],
      limit,
      offset: (page - 1) * limit,
    })
  )

  return <ArticleGrid articles={articles} />
}

Динамические маршруты с ISR

// app/articles/[slug]/page.tsx
import { directus, getDirectusAssetURL } from '@/lib/directus'
import { readItems } from '@directus/sdk'
import { notFound } from 'next/navigation'

export default async function ArticlePage({ params }: { params: { slug: string } }) {
  const articles = await directus.request(
    readItems('articles', {
      fields: ['*', { thumbnail: ['*'] }, { author: ['first_name', 'last_name'] }],
      filter: {
        slug: { _eq: params.slug },
        status: { _eq: 'published' },
      },
      limit: 1,
    })
  )

  const article = articles[0]
  if (!article) notFound()

  return (
    <article>
      {article.thumbnail && (
        <img
          src={getDirectusAssetURL(article.thumbnail.id, { width: '1200', quality: '80' })}
          alt={article.title}
        />
      )}
      <h1>{article.title}</h1>
      <div dangerouslySetInnerHTML={{ __html: article.content }} />
    </article>
  )
}

export async function generateStaticParams() {
  const articles = await directus.request(
    readItems('articles', {
      fields: ['slug'],
      filter: { status: { _eq: 'published' } },
      limit: -1,
    })
  )
  return articles.map(a => ({ slug: a.slug }))
}

export const revalidate = 3600

On-demand Revalidation

// app/api/revalidate/route.ts — принимает вебхук Directus
import { revalidateTag, revalidatePath } from 'next/cache'

export async function POST(req: Request) {
  const secret = req.headers.get('x-webhook-secret')
  if (secret !== process.env.DIRECTUS_WEBHOOK_SECRET) {
    return Response.json({ error: 'Unauthorized' }, { status: 401 })
  }

  const { collection, keys, payload } = await req.json()

  revalidateTag(collection)

  if (collection === 'articles' && payload?.slug) {
    revalidatePath(`/articles/${payload.slug}`)
  }

  return Response.json({ revalidated: true })
}

Клиентский React хук

// hooks/useDirectus.ts
'use client'
import { useState, useEffect } from 'react'

export function useDirectusItems<T>(
  collection: string,
  query: Record<string, any>
): { data: T[]; loading: boolean; error: Error | null } {
  const [data, setData] = useState<T[]>([])
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<Error | null>(null)

  useEffect(() => {
    const params = new URLSearchParams({ query: JSON.stringify(query) })
    fetch(`/api/directus/${collection}?${params}`)
      .then(r => r.json())
      .then(d => setData(d.data || []))
      .catch(setError)
      .finally(() => setLoading(false))
  }, [collection, JSON.stringify(query)])

  return { data, loading, error }
}

Directus Realtime (WebSockets)

// Подписка на изменения в реальном времени
import { createDirectus, realtime } from '@directus/sdk'

const client = createDirectus(DIRECTUS_URL).with(realtime())

await client.connect()
const subscription = await client.subscribe('articles', {
  event: 'update',
  query: { fields: ['id', 'title', 'status'] },
})

for await (const message of subscription) {
  console.log('Article updated:', message.data)
}

Сроки

Интеграция Directus с Next.js (SDK, ISR, вебхуки, TypeScript типы) — 2–3 дня.