JSXのClassNameに文字列と変数を使用して詰まった際の解決策


以前、Reactで簡易的なTwitterのようなアプリを作っていた際、コンポーネントのclassName部分に文字列としてのクラス名と、条件分岐処理によって変数に違うクラス名が入る変数を設置しようとしたのですが、上手く行かずに詰まりました
その時の解決方法をメモします。

何がしたかったのか

自分の場合、あらかじめlikeクラスを持ったspanタグがあり、投稿のいいねアイコンがクリックされるといいねアイコンに着色するlikedクラスを変数liked_classに格納しspanタグにつけようとしました。(今回は一時的に変数名を変えている為、少し命名がおかしいですが、気にしないでください笑)


↑投稿にいいねを付けていない場合(クラスはlikeのみ)

↑投稿にいいねを付けた場合(クラスはlikeと変数liked_classに格納されたliked)

因みにCSSは以下のような感じです。

.like{
        font-size: 30px;
}

.liked{
        color: #FF6699;
}

上記の説明と画像の通りですが、いいねアイコンのspanタグにlikedクラスが付与されると、colorプロパティにより、いいねアイコンが着色されます。

以下、上手く行かなかった際のコードです。

//投稿のlikeフラグ(hasliked)がtrueであればlikedクラスを変数に格納、falseなら空文字列を格納
const liked_class = post.hasLiked() ? 'liked' : '';

    return (
        //spanタグにlikeクラスと上記の処理で定義した変数、liked_classをセットする
        <span className="`like ${liked_class}`" onClick={() => {
            props.likePostToggle(post.id)
        }}>
            <FontAwesomeIcon icon={faThumbsUp} />
        </span>
    );

classNameの中で変数を展開して文字列と連結させようとしたのですが、like ${liked_class}が1つのクラス名と認識され上手く表示されませんでした。

解決方法(classnamesライブラリのClassNamesメソッドを使用)

上記で詰まった点ですが、こちらの記事を参考にしてclassnamesライブラリが提供するClassNamesメソッドを使用することで解決できました。
以下、使い方です。

npm経由でclassnamesライブラリをインストールします。

npm install classnames --save

使用したいコンポーネント内で、classnamesライブラリが提供するclassNamesメソッドをインポートします。

import classNames from 'classnames';

classNameの内に文字列と変数を使用したいところでclassNamesメソッドを使用します。自分の場合は以下のようになりました。

//上記と同じくいいねフラグがtrueの場合likedクラスを変数に格納、falseはの場合空文字を格納
const liked_class = post.hasLiked() ? 'liked' : '';

//classnamesライブラリが提供しているclassNamesメソッドを使用し、使いたい文字列や変数をセットする
    const liked_classes = classNames(
        'like', //あらかじめセットしておく文字列のクラス名
        liked_class //上記の条件分岐処理の結果で中に入るクラス名が変わる変数
    );

    return (
     //上記で定義した変数、liked_classesをclassNameに指定
        <span className={liked_classes} onClick={() => {
            props.likePostToggle(post.id)
        }}>
            <FontAwesomeIcon icon={faThumbsUp} />
        </span>
    );

また以下のように書くこともできます。
上のコードとの違いは、1行目に記述していた、いいねフラグの有無によって変数に格納する値を、likedか空文字列か決めていた部分を部分を削除し、classNamesの内部でいいねフラグがtrueの時のみlikedクラスを付与するようにしています。

以下のコードの方が変数を定義する必要がなくなるのでいいですね。

//ここの処理は不要
const liked_class = post.hasLiked() ? 'liked' : '';

    const liked_classes = classNames(
        'like', //あらかじめセットしておく文字列のクラス名
     //1行目に記述していた条件分岐処理をこちらに記述(いいねフラグがtrueの場合、likedクラスを付与)
        {'liked' : post.hasLiked()} 
    );

    return (
     //上記で定義した変数、liked_classesをclassNameに指定
        <span className={liked_classes} onClick={() => {
            props.likePostToggle(post.id)
        }}>
            <FontAwesomeIcon icon={faThumbsUp} />
        </span>
    );

こうすることで、投稿にいいねがついた場合のみspanタグにlikedクラスを付与し、いいねアイコンに着色することができました!