LoginSignup
7
3

More than 5 years have passed since last update.

Reactコンポーネントの動的スタイル更新 (2)

Last updated at Posted at 2018-11-10

React.jsにおける動的スタイル変更

この記事は、以前書いた、
https://qiita.com/olt/items/c96795e5bdf1058cd547
の手直しを加えた形です。

React.jsのみを用いて動的にスタイル更新

今回はReact.jsのみを用いて動的にスタイル更新を
Stateの管理によって行います。

しかし、昨今ではReduxや最近ではReact Hooksなどを用いて、
Stateの更新を行うことが多いらしい。

ただ、React.jsのクラスコンポーネントを理解するためには、
実際にReact.jsのみでStateの更新を行ってみて、
理解していくのがわかりやすくていいと思っています。

作るもの

大体こんな感じの枠組みを例として作ります。
スクリーンショット 2018-11-10 16.48.04.png

要件

  • CSSのみで管理できる範囲のコンポーネントのスタイルにはCSSを用いる
  • 動的にスタイル操作する必要がある場合、React.jsのStateを用いて管理
  • 極力レスポンシブデザイン
  • 対象はWebアプリケーション

コーディング

前提として、Webpack+bable+Node.jsを用いますが、
ここでの説明を省きます。

まずMain.jsにて、コンポーネント全体のレンダリングを定義します。

Main.js
import React,  {Component} from 'react';
import ReactDOM from 'react-dom';
import {ContentBody} from './ContentBody';

class Main extends Component {
    render() {
        return (
            <ContentBody />
        );
    }
}

ReactDOM.render (
    <Main />,
    document.getElementById("root")
);

export default Main;

次に、レンダリングするコンポーネントの内容を記述していきます。
CSSモジュールを利用していますが、動的に変更を加えるスタイル要素には利用していません。

Component.js
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import styles from '../css/app.css'

export class ContentBody extends Component {
    constructor(props) {
        super(props);
        this.state = {
            message: "",
            num: 0,
            stylesSendButton: {},
            windowSizeSub: {}
        };
        this.sendMessage = this.sendMessage.bind(this);
        this.changeSizeStyles = this.changeSizeStyles.bind(this);
        this.buttonStylesSet = this.buttonStylesSet.bind(this);
    }
    //Windowのロードとリサイズの際にイベントハンドラを設定
    componentWillMount () {
        window.addEventListener('load', () =>{
            this.getInitWindowSize();
        });
        window.addEventListener('resize', () => {
            this.getWindowSize();
            this.changeSizeStyles();
        });
    }
    getInitWindowSize(){
        let width = window.innerWidth
        let height = window.innerHeight; 
        let wsize = {
            width: width,
            height: height
        }
        if(height>=width+160){
            this.setState({stylesSendButton: this.buttonStylesSet("#f2f2f3", width*0.15, height, width*0.815, height*0.02)});
            this.setState({windowSizeSub: wsize});
        } else if(height<width+160){
            this.setState({stylesSendButton: this.buttonStylesSet("#f2f2f3", height*0.12, height, width*0.85, height*0.01)});
            this.setState({windowSizeSub: wsize});
        }
    }
    getWindowSize(){
        let width = window.innerWidth
        let height = window.innerHeight;
        let wsize = {
            width: width,
            height: height,
        }
        this.setState({windowSizeSub: wsize});
    }
    sendMessage(){
        let ws = this.state.stylesSendButton;
        //Buttonが押されたら色を変える
        this.setState({stylesSendButton: this.buttonStylesSet("#999", ws.width, ws.height, ws.left, ws.bottom)});
        //Buttonを押した後に元の色に戻す
        setTimeout(()=>{
            this.setState({stylesSendButton: this.buttonStylesSet("#f2f2f3", ws.width, ws.height, ws.left, ws.bottom)});
        },120);
    }
    //画面サイズが変更された際のスタイル更新
    changeSizeStyles(){
        let ws = this.state.windowSizeSub;
        if(ws.height>=ws.width+160) {
            this.setState({stylesSendButton: this.buttonStylesSet("#f2f2f3", ws.width*0.15, ws.height, ws.width*0.815, ws.height*0.02)});
        } else if(ws.height<ws.width+160) {
            this.setState({stylesSendButton: this.buttonStylesSet("#f2f2f3", ws.height*0.12, ws.width, ws.width*0.85, ws.height*0.01)});
        }
    }
    //Buttonのスタイル用の関数(書き換えるオブジェクト要素のみを引数に)
    buttonStylesSet(color, width, height, left, bottom){
        let ButtonStyles = {
            background: color,
            border: "none",
            position: "absolute",
            float: "left",
            left: left,
            bottom: bottom,
            outline: 0,
            display: "block",
            width: width+"px",
            height: width+"px"
        }
        return ButtonStyles;
    }
    render() {
        return (
            <div className={styles.MainBody} >
                <div className={styles.header} />
                <div className={styles.footer}>
                    <div>
                        <textarea className={styles.textarea1} 
                            input type="text" 
                            value={this.state.message} 
                            onChange={(e)=>this.setState({message:e.target.value})}
                        />
                        <button id ="button" style={this.state.stylesSendButton}
                            onClick={this.sendMessage.bind(this)}
                        />
                    </div>
                </div>
            </div>
        );
    }
}

上記のコード中で用いているスタイル用の関数を用いることで、
動的にスタイルを更新する際に、
わざわざスタイル用のオブジェクトを再定義する必要がなくなります。

スタイル用の関数を最低限の変数を引数に設定して呼び出し、
その返り値をsetSate()の引数にすることで、ある程度の冗長性を
抑えられるのではないかなと思います。

CSSはこちら

app.css
.html{
    border: none;
}
.body{
    border: none;
}
.MainBody{
    border: none;
    background-color:#91c0fa;
    position: absolute;
    left: 0%;
    bottom:0%;
    height: 100%;
    width: 100%;
}
.header{
    background-color:rgb(207, 204, 204);
    box-shadow: rgb(214, 214, 214);
    border: none;
    float: left;
    position: absolute;
    width: 100%;
    height: 10%;
    top: 0%;
}
.footer{
    background-color:rgb(207, 204, 204);
    box-shadow: rgb(214, 214, 214);
    border: none;
    float: left;
    position: absolute;
    width: 100%;
    height: 15%;
    bottom: 0%;
}
.textarea1{
    background-color:rgb(255, 255, 255);
    position: absolute;
    float: left;
    width: 70%;
    height: 75%;
    left: 5%;
    bottom: 8%;
    resize: none;
    outline: 0;
}

今後はReactのStateの更新用のライブラリなども
調べていきたいですが、その際のおすすめや
今回のアドバイスなどあればコメントよろしくお願いします。

7
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
3