Reactコンポーネントのスタイルを切り替えるにはどうしたらいいですか?

  • 2
    いいね
  • 0
    コメント

これは「コードを書いていて困ったときに、suinがチャットで質問に答えたり相談に乗るsuinのプログラミング相談室(仮)」で頂いた質問と僕の回答の要約です。

質問

Reactで同じコンポーネントに違うスタイルを当てるにはどのようにしたらいいですか? ABテストを考えていて、ある条件ではスタイルAを、別の条件ではスタイルBを当てられるようにしたいです。

suinの回答

CSSで解決する方法と、Reactで解決する方法の2つが考えられます。

CSSで解決する方法

例えば、ReactのAppモジュールではappクラスを決め打ちにしておいて、ReactがレンダリングされるDOMをclass="red"class="blue"で囲めば、.red .app.blue .appでそれぞれ別のスタイルが適用できます。React外の技術でアプローチするパターンですね。

<div class="red">
    <div id="root"></div>
</div>

<div class="blue">
    <div id="root"></div>
</div>
class App extends React.Component {
    render () {
        return <div className="app">App!</div>
    }
}

ReactDOM.render(<App />, document.getElementById('root'))
.red .app {
    color: red;
}

.blue .app {
    color: blue;
}

Reactで解決する方法

Reactでやる場合は、コンポーネントの設定値をコンポーネント使う側から渡せるようにします。

class App extends React.Component {
    // 属性情報のバリデーション
    static propTypes = {
        taste: React.PropTypes.string.isRequired
    }

    // 親からXML属性で受け取れるようにする
    constructor (props) {
        super(props)
        this.state = {...なにかあれば...}
    }

    render () {
        console.log(this.props) // ここで taste 属性があるはず

        // ここでスタイルを切り替える
        const className = this.props.taste === 'red' ? 'red-app' : 'blue-app'

        // たしかこれでいいはず
        return <div className={className}>App!</div>
    }
}

// コンポーネントを使う側
ReactDOM.render(<App taste="red" />, document.getElementById('red-app'))
ReactDOM.render(<App taste="blue" />, document.getElementById('blue-app'))
<div id="red-app"></div>
<div id="blue-app"></div>
.red-app {
    color: red;
}

.blue-app {
    color: blue;
}

PHP(サーバサイド)側で動的にスタイルを指定する場合

ちなみに、サーバサイドでスタイルを動的に指定する場合はこうです。まず、PHP側では動的にdata-tasteを書き出すようにします。

<?php
$taste = $someCondition ? 'red' : 'blue';
echo '<div id="app" data-taste="' . $taste . '"></div>';

サーバサイドのロジックによって

<div id="app" data-taste="red"></div> 

などが描画されます。

JSではそれを受け取れるようにします。

main.js
const element = document.getElementById('#app')

console.log(element.dataset)
console.log(element.dataset.taste) // あるはず

const dataset = JSON.parse(JSON.stringify(element.dataset)); // Object.assignがSafariではうまくいかないため
ReactDom.render(<App {...dataset} />, element);

ちなみにこのテクは、僕が作ったQiita Widgetで使っています。このへんのコードです→https://github.com/suin/qiita-widget/blob/master/src/main.js#L10

回答に対しての反応

おお、今か書いて下さったdatasetで切り替えるのが良さそうです! Safariでダメなのも知らなかったです。