Poznajemy obiekt FormData w JS oraz to, jak możemy z niego skorzystać w React. Do dzieła.
Ok, obiekt FormData przyjmuje formularz, oraz opcjonalnie submitter (submit button):
const form = document.getElementById("form");
const submitter = document.querySelector("button[value=save]");
const formData = new FormData(form, submitter);
Obiekt posiada iterator i możemy iterować po tym:
const output = document.getElementById("output");
for (const [key, value] of formData) {
output.textContent += `${key}: ${value}\n`;
}
Już teraz powinniśmy się domyślać, że iterator zwraca pseudotuple klucz-wartość. FormData posiada metodę append:
formData.append("username", "Chris");
Key (atrybut name w HTMLInputElement) i value. Jeżeli value to blob (plik) to jeszcze mamy opcjonalne filename:
formData.append("userpic", myFileInput.files[0], "chris.jpg");
Inne metody:
- fd.has(key) – zwraca czy ma taką wartość
- fd.delete(key) – usuwa z formdata taką wartość
- fd.get(key) – pobiera wartość o podanym kluczu
- fd.set(key,val) – ustawia wartość o kluczu i val jak podane
- fd.set(key,blob, filename) – to do plików, jak val jest blobem podajemy opcjonalnie filename, inaczej nazywa się blob (dla blobów utworzonych w pamięci przez konstruktor) lub jeśli jest plikiem uploadowanym formularzem to bierze od pliku filename
- fd.getAll(key) – w przypadku każdego HTMLInputElement zwraca wynik jako tablicę, w przypadku type checkbox to jedyny sposób na to, aby uzyskać wszystkie zaznaczone elementy o takim samym name
Pamiętajmy, nazwa klucza w FormData to jest atrybut name w HTMLInputElement. Tylko te elementy mają taki atrybut, mają też value (to jest wartość) oraz inne atrybuty typu class, id, standardowe dla HTMLElement.
Ok, oto przykład użycia FormData w React:
import { useState } from 'react';
export default function Signup() {
const [passwordsAreNotEqual, setPasswordsAreNotEqual] = useState(false);
function handleSubmit(event) {
event.preventDefault();
const fd = new FormData(event.target);
const acquisitionChannel = fd.getAll('acquisition');
const data = Object.fromEntries(fd.entries());
data.acquisition = acquisitionChannel;
if (data.password !== data['confirm-password']) {
setPasswordsAreNotEqual(true);
return;
}
console.log(data);
}
return (
<form onSubmit={handleSubmit}>
Czyli co się dzieje:
- Mamy stan, który ma pokazywać, czy jest ok z hasłami czy nie
- Mamy form z atrybutem onSubmit, który pokazuje na handler
- Mamy handler, który po pierwsze robi prevent default (blokuje odświeżanie strony)
- tworzymy fd, event.target to form
- Bierzemy jakieś dane z checkboxów (inaczej nie robilibyśmy fd.getAll)
- Bierzemy wszystkie dane z formularza robiąc z nich obiekt, do którego wrzucamy fd.entries (które ma pseudotuple name-value)
- Wiemy, że fd.entries ogarnie tylko proste rzeczy typu name-value. I zamieni nam na obiekt, ale pod tym acquisition to ktoś mógł kilka rzeczy zaznaczyć (checkbox) i będzie tylko jedno value (raczej ostatnie)
- Całe szczęście już to acquisition sobie pobraliśmy jako tablicę poprawnie, więc pozostaje tylko nadpisać
- Dalej jest sprawdzanie, czy hasła są ok, zmiana stanu jak nie i return
- Dalej console.log bo to raczej jakaś treningowa lekcja niż skończony projekt (kod znaleziony na Githubie)
I to by było na tyle, dodam od siebie, że React pracuje nad eksperymentalnym, nowym hookiem useActionState, który, zdaje się, będzie korzystać z obiektu FormData, więc to nie są takie głupoty wymyślane przez ludzi, którym się nudzi, to wszystko warto znać, trzeba znać i bardzo ułatwia pracę.