W artykule przedstawię w jaki sposób możemy dostać się do własnych atrybutów oraz atrybutu data-* w elementach HTML przy wykorzystaniu React. W atrybutach możemy przekazać dodatkowe dane, które wykorzystamy np. w logice w aplikacji.
Trzeba jednak wspomnieć, że przekazywanie danych przez atrybuty HTML nie jest rekomendowanym sposobem, o czym możemy przeczytać na oficjalnej stronie Reacta. Warto natomiast wiedzieć, że taka możliwość istnieje. Warto też wiedzieć jak z tego skorzystać, bo być może gdzieś zobaczymy podobny fragment kodu w Reactowych aplikacjach.

Czym są atrybuty?

W przypadku HTMLowych elementów atrybutem będzie zarówno href w elemencie <a> lub src w elemencie <img> itd…

My z kolei skupimy się na atrybucie data-*, który możemy dodać do elementu HTML. Z tego atrybutu będziemy korzystać w naszym przykładzie.

<ul>
    <li data-gender="male">Adam</li>
    <li data-gender="male">Zenek</li>
    <li data-gender="male">Mirek</li>
    <li data-gender="female">Basia</li>
    <li data-gender="female">Zosia</li>
    <li data-gender="female">Czesia</li>
</ul>

Wykorzystanie w React

Wyobraźmy sobie, że dla powyższego przykładu i listy osób chcemy zrobić obsługę głosowania. Każda osoba posiada id oraz daną pomocniczą, służącą np. do statystyk. Zmodyfikujemy nieco nasz kod dodając teraz atrybut id.

<ul>
   <li data-id="1" data-gender="male">Adam</li>
   <li data-id="2" data-gender="male">Zenek</li>
   <li data-id="3" data-gender="male">Mirek</li>
   <li data-id="4" data-gender="female">Basia</li>
   <li data-id="5" data-gender="female">Zosia</li>
   <li data-id="6" data-gender="female">Czesia</li>
</ul>

Przeróbmy to teraz, aby było bardziej „Reactowo”. 🙂

function App() {
    const people = [
        {id: 1, name: 'Adam', gender: 'male'},
        {id: 2, name: 'Zenek', gender: 'male'},
        {id: 3, name: 'Mirek', gender: 'male'},
        {id: 4, name: 'Basia', gender: 'female'},
        {id: 5, name: 'Zosia', gender: 'female'},
        {id: 6, name: 'Czesia', gender: 'female'},
    ];
    return (
         <ul>
            {people.map((person) => (
                <li key={person.id} data-id={person.id} data-gender={person.gender}>
                    {person.name}
                </li>
            ))}
        </ul>
    );
}

Musimy teraz sprawić, aby po kliknięciu w dany <li> nastąpiło wywołanie eventu z odpowiednim id elementu.

Dodajemy sobie kawałek kodu, w którym w realnej aplikacji byłaby obsługa logiki. Dodajemy obsługę onClick oraz metodę obsługującą głosowanie.

<li
    key={person.id}
    data-id={person.id}
    data-gender={person.gender}
    onClick={vote}
>
    {person.name}
</li>
const vote = (event) => {
    console.log(event);
    console.log(event.target.dataset);
}

Jeżeli włączycie konsolę i kliknięcie w dany element listy, powinniście widzieć w niej coś w stylu:

Class {dispatchConfig: {…}, _targetInst: FiberNode, nativeEvent: MouseEvent, type: "click", target: li, …}
DOMStringMap {id: "6", gender: "female"}
gender: "female"
id: "6"
__proto__: DOMStringMap

Jak widzicie, uzyskaliśmy dostęp do atrytubów data-gender oraz data-id. W ten sposób możemy wykorzystać te dane do logiki.

Możemy również w elegancki sposób użyć destrukturyzacji, a potem bezpośrednio użyć wartości z data-id oraz data-gender.

const vote = (event) => {
    const { id, gender } = event.target.dataset;
    console.log(id);
    console.log(gender);
}

Własny atrybut

Możemy również dodać własny atrybut i odwołać się do jego wartości. W poniższym kodzie dodaliśmy atrybut wraz z wartością mojjakisatrybut="some value". Dostęp do niego odbywa się poprzez event.target.getAttribute('mojjakisatrybut').

const vote = (event) => {
    console.log(event.target.getAttribute('mojjakisatrybut'))
}

return (
    <ul>
        {people.map((person) => (
            <li
                key={person.id}
                mojjakisatrybut="some value"
                onClick={vote}
            >
                {person.name}
            </li>
        ))}
    </ul>
)

Pamiętajmy, aby własne atrybuty nazywać małymi literami, o czym informuje nas poniższy warning.

Warning: React does not recognize the `mojJakisAtrybut` prop on a DOM element. If you intentionally want it to appear in the DOM as a custom attribute, spell it as lowercase `mojjakisatrybut` instead. If you accidentally passed it from a parent component, remove it from the DOM element.

React i atrybuty

Na stronie Reacta możemy znaleźć informację, w której autorzy nie zachęcają do przekazywania danych poprzez własne atrybuty.
Nawet jeżeli używamy atrybutu data-* (a nie własnego atrybutu), zapewne lepszym rozwiązaniem będzie przechowywanie danych w state komponentu lub zewnętrznym „store”. Możemy o tym przeczytać tutaj: https://pl.reactjs.org/blog/2017/09/08/dom-attributes-in-react-16.html

Niemniej jednak warto wspomnieć, że takie możliwości istnieją. Może gdzieś spotkamy się z takim rozwiązaniem, będziemy wtedy wiedzieć skąd to się bierze i jak sobie z tym poradzić.
Do następnego, dzięki!

Źródła:
Obraz: https://unsplash.com/photos/eo3Xr2yhYVw
Oficjalna www React i trochę informacji na temat atrybutów: https://pl.reactjs.org/blog/2017/09/08/dom-attributes-in-react-16.html