@company-manager/docs
Development

Gestion d'État

Guide complet de la gestion d'état dans Company Manager.

Gestion d'État

Guide complet pour gérer l'état de l'application dans Company Manager.

Vue d'Ensemble

Company Manager utilise une combinaison de solutions de gestion d'état :

  • Zustand pour l'état global
  • React Query pour l'état serveur
  • React Hook Form pour l'état des formulaires
  • Context API pour l'état partagé local

Zustand

Configuration de Base

// stores/useStore.ts
import { create } from "zustand";

interface Store {
  // État
  count: number;
  user: User | null;

  // Actions
  increment: () => void;
  setUser: (user: User | null) => void;
}

export const useStore = create<Store>((set) => ({
  // État initial
  count: 0,
  user: null,

  // Actions
  increment: () => set((state) => ({ count: state.count + 1 })),
  setUser: (user) => set({ user }),
}));

Utilisation

const Component = () => {
  const { count, increment } = useStore();

  return (
    <button onClick={increment}>
      Count: {count}
    </button>
  );
};

Slices

// stores/slices/authSlice.ts
interface AuthSlice {
  user: User | null;
  setUser: (user: User | null) => void;
}

export const createAuthSlice: StateCreator<AuthSlice> = (set) => ({
  user: null,
  setUser: (user) => set({ user }),
});

// stores/useStore.ts
interface Store extends AuthSlice {
  // ... autres slices
}

export const useStore = create<Store>()((...a) => ({
  ...createAuthSlice(...a),
  // ... autres slices
}));

React Query

Configuration

// lib/queryClient.ts
import { QueryClient } from "@tanstack/react-query";

export const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: 5 * 60 * 1000, // 5 minutes
      cacheTime: 10 * 60 * 1000, // 10 minutes
    },
  },
});

Hooks Personnalisés

// hooks/useUsers.ts
export const useUsers = (params: UserParams) => {
  return useQuery({
    queryKey: ["users", params],
    queryFn: () => fetchUsers(params),
    select: (data) => data.map(transformUser),
  });
};

// hooks/useUpdateUser.ts
export const useUpdateUser = () => {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: updateUser,
    onSuccess: (data) => {
      queryClient.setQueryData(["user", data.id], data);
      queryClient.invalidateQueries(["users"]);
    },
  });
};

Utilisation

const UserList = () => {
  const { data, isLoading } = useUsers({ status: 'active' });
  const { mutate: updateUser } = useUpdateUser();

  if (isLoading) return <Spinner />;

  return (
    <div>
      {data?.map((user) => (
        <UserCard
          key={user.id}
          user={user}
          onUpdate={updateUser}
        />
      ))}
    </div>
  );
};

React Hook Form

Configuration de Base

// components/UserForm.tsx
interface FormData {
  name: string;
  email: string;
  role: string;
}

const UserForm = () => {
  const form = useForm<FormData>({
    defaultValues: {
      role: 'user',
    },
    resolver: zodResolver(userSchema),
  });

  const onSubmit = async (data: FormData) => {
    await createUser(data);
  };

  return (
    <Form {...form}>
      <FormField
        name="name"
        label="Nom"
        control={form.control}
      />
      {/* ... autres champs */}
    </Form>
  );
};

Validation

// schemas/userSchema.ts
import { z } from "zod/v4";

export const userSchema = z.object({
  name: z.string().min(2),
  email: z.string().email(),
  role: z.enum(["user", "admin"]),
});

Context API

Création du Contexte

// contexts/ThemeContext.tsx
interface ThemeContextType {
  theme: Theme;
  setTheme: (theme: Theme) => void;
}

const ThemeContext = createContext<ThemeContextType | undefined>(undefined);

export const ThemeProvider: FC<PropsWithChildren> = ({ children }) => {
  const [theme, setTheme] = useState<Theme>('light');

  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      {children}
    </ThemeContext.Provider>
  );
};

export const useTheme = () => {
  const context = useContext(ThemeContext);
  if (!context) {
    throw new Error('useTheme must be used within ThemeProvider');
  }
  return context;
};

Persistence

Local Storage

// stores/usePersistedStore.ts
import { persist } from "zustand/middleware";

export const usePersistedStore = create(
  persist(
    (set) => ({
      settings: defaultSettings,
      updateSettings: (settings: Settings) => set({ settings }),
    }),
    {
      name: "settings-storage",
    }
  )
);

Bonnes Pratiques

  1. Sélection de l'Outil

    • Zustand pour l'état global simple
    • React Query pour les données serveur
    • Context pour l'état partagé local
    • Local state pour l'état composant
  2. Performance

    • Éviter le re-render inutile
    • Utiliser la mémoisation
    • Optimiser les sélecteurs
  3. Organisation

    • Structure claire des stores
    • Séparation des préoccupations
    • Documentation des interfaces