DeenruvDeenruv
Rozszerzanie panelu administracyjnego

Zarządzanie stanem

Globalne store oparte na Zustand w @deenruv/react-ui-devkit — ustawienia, serwer, zamówienia i więcej

@deenruv/react-ui-devkit wykorzystuje Zustand do globalnego zarządzania stanem. Kilka store jest dostarczanych od razu do użytku, umożliwiając dostęp do stanu panelu administracyjnego — uwierzytelniania, wyboru kanału, konfiguracji serwera i innych.

useSettings

Główny utrwalany store ustawień panelu administracyjnego. Przechowuje stan uwierzytelniania, preferencje interfejsu i aktywny kanał/język.

import { useSettings } from '@deenruv/react-ui-devkit';

function MyComponent() {
  // Wybieraj poszczególne wartości dla optymalnych re-renderów
  const token = useSettings((s) => s.token);
  const selectedChannel = useSettings((s) => s.selectedChannel);
  const translationsLanguage = useSettings((s) => s.translationsLanguage);
  const logIn = useSettings((s) => s.logIn);
  const logOut = useSettings((s) => s.logOut);

  // Sprawdzenie uwierzytelniania
  if (!token) {
    return <div>Not authenticated</div>;
  }

  return (
    <div>
      <p>Channel: {selectedChannel?.code}</p>
      <p>Language: {translationsLanguage}</p>
      <Button onClick={logOut}>Log Out</Button>
    </div>
  );
}

Kluczowe właściwości

WłaściwośćTypOpis
tokenstring | nullAktualny token Bearer uwierzytelniania
selectedChannelChannel | nullAktualnie aktywny kanał
translationsLanguageLanguageCodeJęzyk tłumaczeń encji
theme'light' | 'dark'Aktualny motyw interfejsu
logIn(credentials) => Promise<void>Akcja logowania
logOut() => voidAkcja wylogowania

useSettings jest utrwalany — jego stan przetrwa przeładowanie strony. Używaj wzorca selektorów Zustand (jak pokazano wyżej), aby subskrybować tylko te konkretne wartości, których Twój komponent potrzebuje. Zapobiega to zbędnym re-renderom.

useServer

Przechowuje stan połączenia z serwerem, dostępne kanały, uprawnienia i globalną konfigurację:

import { useServer } from '@deenruv/react-ui-devkit';

function ChannelPicker() {
  const channels = useServer((s) => s.channels);
  const permissions = useServer((s) => s.permissions);
  const serverConfig = useServer((s) => s.serverConfig);

  return (
    <div>
      <p>Available channels: {channels.length}</p>
      <p>Custom fields config: {JSON.stringify(serverConfig?.customFieldConfig)}</p>
      {permissions.includes('CreateProduct') && (
        <Button>Create Product</Button>
      )}
    </div>
  );
}

Kluczowe właściwości

WłaściwośćTypOpis
channelsChannel[]Wszystkie dostępne kanały
permissionsstring[]Uprawnienia aktualnego użytkownika
serverConfigServerConfigKonfiguracja serwera, w tym definicje pól niestandardowych

useOrder

Zarządzanie stanem specyficznym dla zamówień w widoku szczegółów zamówienia:

import { useOrder } from '@deenruv/react-ui-devkit';

function OrderActions() {
  const order = useOrder((s) => s.order);
  const refetch = useOrder((s) => s.refetch);

  return (
    <div>
      <p>Order #{order?.code} — {order?.state}</p>
      <Button onClick={refetch}>Refresh</Button>
    </div>
  );
}

useGlobalSearch

Globalny stan wyszukiwania dla paska wyszukiwania panelu administracyjnego:

import { useGlobalSearch } from '@deenruv/react-ui-devkit';

function SearchComponent() {
  const searchTerm = useGlobalSearch((s) => s.searchTerm);
  const setSearchTerm = useGlobalSearch((s) => s.setSearchTerm);
  const results = useGlobalSearch((s) => s.results);

  return (
    <div>
      <Input
        value={searchTerm}
        onChange={(e) => setSearchTerm(e.target.value)}
        placeholder="Search..."
      />
      {results.map((result) => (
        <div key={result.id}>{result.name}</div>
      ))}
    </div>
  );
}

GlobalStoreProvider / useGlobalStore

Provider globalnego store oparty na kontekście dla stanu całej aplikacji. Używany wewnętrznie przez panel administracyjny:

import { useGlobalStore } from '@deenruv/react-ui-devkit';

function MyComponent() {
  const globalState = useGlobalStore();
  // Dostęp do stanu całej aplikacji
}

Kiedy używać store vs konfiguracji pluginu

Przypadek użyciaPodejście
Dostęp do tokenu auth, języka, kanałuuseSettings
Sprawdzanie uprawnień użytkownikauseServer
Dostęp do konfiguracji serwerauseServer
Przechowywanie ustawień specyficznych dla pluginuWłaściwość config pluginu
Tymczasowy stan UIReact useState lub useReducer
Stan formularzauseDeenruvForm ze schematem Zod
Stan listy/paginacjiuseList

Konfiguracja pluginu dla niestandardowych ustawień

Jeśli Twój plugin potrzebuje własnej konfiguracji, użyj punktu rozszerzenia config:

import { createDeenruvUIPlugin } from '@deenruv/react-ui-devkit';

interface MyPluginConfig {
  apiEndpoint: string;
  maxItems: number;
  features: {
    enableNotifications: boolean;
    enableWidgets: boolean;
  };
}

export const MyPlugin = createDeenruvUIPlugin<MyPluginConfig>({
  name: 'my-plugin-ui',
  version: '1.0.0',
  config: {
    apiEndpoint: '/api/my-plugin',
    maxItems: 50,
    features: {
      enableNotifications: true,
      enableWidgets: false,
    },
  },
  // ...inne punkty rozszerzenia
});

Najlepsze praktyki

Używaj selektorów dla wydajności

Zawsze używaj funkcji selektorów ze store Zustand, aby zapobiec zbędnym re-renderom:

// ✅ Dobrze — re-renderuje się tylko gdy zmieni się token
const token = useSettings((s) => s.token);

// ❌ Źle — re-renderuje się przy każdej aktualizacji store
const settings = useSettings();
const token = settings.token;

Derywuj stan gdy to możliwe

Zamiast przechowywać wartości pochodne, obliczaj je z istniejącego stanu store:

function MyComponent() {
  const token = useSettings((s) => s.token);
  const isAuthenticated = !!token;   // Derywowane, nie przechowywane

  const permissions = useServer((s) => s.permissions);
  const canCreateProducts = permissions.includes('CreateProduct');  // Derywowane
}

Łącz ze wzorcami React Query

Store Zustand dobrze współpracują z hookami useQuery / useMutation do pobierania danych:

function ProductPage() {
  // Globalny stan ze store
  const channel = useSettings((s) => s.selectedChannel);
  const language = useSettings((s) => s.translationsLanguage);

  // Pobieranie danych z hookami
  const { data, loading } = useQuery(
    (vars) => apiClient('query')({
      product: [{ id: vars.id }, productSelector],
    }),
    { initialVariables: { id: productId } },
  );

  // Stan formularza z useDeenruvForm
  const form = useDeenruvForm({
    schema: z.object({
      name: z.string().min(1, 'Wymagane'),
      slug: z.string(),
    }),
    defaultValues: {
      name: data?.product.name ?? '',
      slug: data?.product.slug ?? '',
    },
  });
}

Na tej stronie