Myślę, że przy piątku lepiej będzie napisać coś trochę lżejszego. Pozostajemy jednak w tematyce ReactJS! Dziś przedstawię Ci prosty sposób na dynamiczna wartość atrybutu className. Osiągniemy to dzięki jednej sprytnej bibliotece… Używam jej w praktycznie każdym komponencie prezentacyjnym - moim zdaniem jest na prawdę bardzo przydatna. Zresztą za chwilę sam się przekonasz.

Dynamiczna wartość atrybutu className

Zanim przedstawię Ci wspomnianą bibliotekę, dla porządku wspomnę jak dynamiczna wartość atrybutu className osiągalna jest standardowo, bez użycia zewnętrznych bibliotek. Spójrz na poniższy przykład komponentu ReactJS:

import React from 'react';

const exampleComponent = (props) => {
  const isActive = props.isActive ? 'active' : '';
  const isEnabled = props.isEnabled ? 'enabled' : '';

  return (
    <div className={`container ${isActive} ${isEnabled}`}>
      ...
    </div>
  );
};

export defaut exampleComponent;

Jak widzisz, komponent exampleComponent zwraca element div, któremu nadaję trzy klasy CSS. Pierwsza z nich to ustawiona na sztywno klasa container. Dwie następne ustawiane są dynamicznie. Dynamiczne dlatego, że w zależności od wartości parametru dostępnego w “propsach” mają one inną wartość.

Dodatkowo zwróć też uwagę w jaki sposób definiuję wartość atrybutu className. Jest to zapis dostępny w ES6, pozwalający na parametryzowanie ciągów znaków. Jak widzisz, aby przekazać do “stringa” parametr, używamy zapisu ${zmienna}.

Tak mniej więcej wygląda standardowy sposób na definiowanie dynamicznych wartości parametru className. Nie wygląda to źle choć można się domyślić, że kiedy parametrów będzie dużo, definicja atrybutu className zrobi się dość rozbudowana…

Na szczęście ktoś już o tym pomyślał i stworzył dedykowaną bibliotekę!

Zróbmy to lepiej - biblioteka classnames

No dobrze, czas przedstawić głównego bohatera dzisiejszego wpisu czyli bibliotekę classnames - tutaj link do projektu na GitHub. Generalnie służy ona po prostu do warunkowego łączenia ciągów znaków w jeden ciąg wynikowy.

Zanim przejdziemy dalej, sprawdźmy jak zainstalować, a później używać tej biblioteki.

Instalacja i użycie

Jak wszystko w świecie ReactJS, bibliotekę classnames instaluje się za pomocą NPM:

npm install classnames

Teraz możesz już zwyczajnie zaimportować classnames w swoim module.

Czas teraz przejść do przykładowego użycia tej biblioteki. Jest to bardzo proste. Spójrz na poniższy przykład (zaczerpnięty z pliku README biblioteki):

import classNames from 'classnames';

classNames('foo', 'bar'); // => 'foo bar'
classNames('foo', { bar: true }); // => 'foo bar'
classNames({ 'foo-bar': true }); // => 'foo-bar'
classNames({ 'foo-bar': false }); // => ''
classNames({ foo: true }, { bar: true }); // => 'foo bar'
classNames({ foo: true, bar: true }); // => 'foo bar'

// lots of arguments of various types
classNames('foo', { bar: true, duck: false }, 'baz', { quux: true });
// => 'foo bar baz quux'

// other falsy values are just ignored
classNames(null, false, 'bar', undefined, 0, 1, { baz: null }, '');
// => 'bar 1'<br>

Jak widzisz funkcja classNames, którą zaimportowaliśmy w pierwszej linii przykładu przyjmuje ciągi znaków i/lub obiekty jako parametry. Jeśli przekażesz same “stringi”, metoda classNames zwyczajnie połączy je używając znaku spacji jako separatora.

Drugi i bardziej interesujący sposób to przekazanie obiektu jako parametr. Właściwości tego obiektu powinny mieć przypisane wartości typu bool. Jeśli przypiszesz do właściwości wartość true to nazwa tej właściwości znajdzie się w wynikowym ciągu znaków. Jeżeli natomiast przypiszesz jej wartość false, to zostanie ona pominięta. Tak, to jest tak proste!

Funkcja classNames jako dynamiczna wartość atrybutu className

No dobra. Myślę, że wiemy już wszystko co potrzeba aby wykorzystać bibliotekę classnames w naszym przykładowym komponencie. Spójrzmy na zmodyfikowany komponent exampleComponent, w którym wykorzystałem funkcję classNames:

import React from 'react';
import classNames from 'classnames';

const exampleComponent = (props) => {
  const classValue = classNames({
    'container': true,
    'active': props.isActive,
    'enabled': props.isEnabled
  });

  return (
    <div className={classValue}>
      ...
    </div>
  );
};

export defaut exampleComponent;

W powyższym przykładzie użyłem funkcji classNames do przygotowania ciągu znaków, który przekazuję do atrybutu className elementu div.

Zwróć uwagę na obiekt, który przekazuję do funkcji classNames. Jego właściwość container jest ustawiona na true więc po prostu zostanie ona wrzucona do wynikowego “stringa”. Pozostałe właściwości zależą od właściwości obiektu props. W zależności od tego jakie są te wartości, nazwy właściwości obiektów trafią do wynikowego ciągu lub nie. W efekcie do zmiennej classValue przypisany zostanie ciąg znaków zawierający odpowiednie nazwy właściwości oddzielone spacją.

Jeśli spojrzysz teraz na element div zauważysz, że tym razem do jego atrybutu className przekazuję po prostu zmienną, do której przypisałem wynik działania funkcji classNames. Element ten, ma więc teraz nadane odpowiednie klasy.

Wydaje mi się, że powyższy zapis jest znacznie bardziej czytelny. Osobiście zawsze stosuję bibliotekę classnames przy tworzeniu dynamicznych wartości atrybutu className.

Podsumowanie

To tyle na dziś. Mam nadzieję, że przedstawiona przeze mnie biblioteka okaże się dla Ciebie przydatna. Ciekaw jestem Twojej opinii o przedstawionym dziś podejściu…

Jako uzupełnienie powyższego artykuły stworzyłem również video tutorial, dostępny na moim kanale w serwisie youtube. Zachęcam do subskrypcji tego kanału, ponieważ na pewno będą się tam pojawiać kolejne video tutoriale! Poniżej przedstawiam wspomniany film: