Zduplikowany kod to zawsze miejsce, aby się zatrzymać i zastanowić, jak go ujednolicić.

Napotkałem ostatnio problem z duplikacją kodu w mojej aplikacji. Dwie różne trasy (route’y) prowadziły do dwóch różnych formularzy, które w praktyce robiły dokładnie to samo. Chodziło o formularze do tworzenia oraz edytowania jednej encji. Zacząłem się zastanawiać, czy faktycznie potrzebuję dwóch osobnych formularzy.

Identyfikacja problemu

Przy bliższym przyjrzeniu się zauważyłem, że:

  • Oba formularze miały identyczne pola i walidacje.
  • Różniły się jedynie sposobem pobierania początkowych wartości oraz akcją wykonywaną po kliknięciu przycisku „Zapisz” lub „Utwórz”.
  • Każda zmiana w jednym formularzu musiała być powtarzana w drugim, co prowadziło do błędów i było trudne w utrzymaniu.

Początkowe przykłady formularzy (duplikacja)

Formularz do dodawania:


<form onSubmit={createEntity}>
  <input name="name" placeholder="Nazwa" />
  <input name="address" placeholder="Adres" />
  <input name="nip" placeholder="NIP" />
  <input name="regon" placeholder="Regon" />
  <button type="submit">Utwórz</button>
</form>

Formularz do edycji:


<form onSubmit={editEntity}>
  <input name="name" value={entity.name} />
  <input name="address" value={entity.address} />
  <input name="nip" value={entity.nip} />
  <input name="regon" value={entity.regon} />
  <button type="submit">Zapisz zmiany</button>
</form>

Jest tu widoczna wyraźna przestrzeń do optymalizacji.

Rozwiązanie

Postanowiłem stworzyć jeden dynamiczny formularz, który w zależności od parametru identyfikującego dane:

  • jeśli parametr istnieje – formularz pobiera dane z API i wypełnia pola (edycja),
  • jeśli nie – formularz pozostaje pusty (dodawanie).

Implementacja (przykład z SolidJS)

W moim przypadku używaliśmy solid-routera dla tras:

  • entity/:id/new
  • entity/:id/edit

Pobranie parametru z URL:


const params = useParams();

Pobieranie danych, jeśli parametr istnieje:


const [data] = createResource(params.id, fetchDataById);

Ustawianie wartości początkowych formularza:


const [formState, setFormState] = createSignal({ name: "", address: "", nip: "", regon: "" });

createEffect(() => {
  if (data()) setFormState({ ...data() });
});

Dynamiczna obsługa wysłania formularza:


async function handleSubmit(e) {
  e.preventDefault();
  const currentData = formState();

  if (params.id) {
    await updateData(params.id, currentData);
  } else {
    await createData(currentData);
  }
}

Renderowanie dynamicznych elementów:


<h2>{params.id ? "Edytuj dane" : "Dodaj nowe dane"}</h2>
<button type="submit">{params.id ? "Zapisz zmiany" : "Utwórz"}</button>

Korzyści z zastosowania tego rozwiązania

  • Usunięcie duplikacji kodu
  • Uproszczenie testowania
  • Łatwiejsze utrzymanie i rozwój aplikacji
  • Spójny interfejs użytkownika, bardziej intuicyjny dla użytkownika końcowego

Podsumowanie

Dynamiczny formularz pozwala znacząco uprościć kod aplikacji, zmniejszyć ryzyko błędów i poprawić jej czytelność oraz komfort utrzymania. Szczególnie w aplikacjach SPA warto rozważyć wdrożenie tego podejścia, aby zapewnić jednolite doświadczenie użytkownikom oraz ułatwić rozwój projektu.


Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *