読者です 読者をやめる 読者になる 読者になる

Djangoroidの奮闘記

python,django,angularJS1~三十路過ぎたプログラマーの奮闘記

Reactに挑戦してみる 8

概要

Reactに挑戦してみる8。ここから少し複雑になりそう。

参考書籍

WebデベロッパーのためのReact開発入門 JavaScript UIライブラリの基本と活用

WebデベロッパーのためのReact開発入門 JavaScript UIライブラリの基本と活用

Reactで使うフォーム~HTMLとの比較

Reactは、条件に応じて、表示させる項目を変えたりする時に便利。

form.html

<!DOCTYPE html>
<html>
  <head>
      <meta charset="utf-8">
      <title>Text Input Example</title>
      <script src="http://cdnjs.cloudflare.com/ajax/libs/react/15.3.0/react.js"></script>
      <script src="http://cdnjs.cloudflare.com/ajax/libs/react/15.3.0/react-dom.js"></script>
      <script src="http://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.24/browser.min.js"></script>
  </head>
  <body>
    <div>HTML Input: <input type="text" value="入力欄" /></div>
    <div id="content"></div>
    <script type="text/babel" src="textinput.js"></script>
  </body>
</html>

textinput.js

var TextInput = React.createClass({
    render: function(){
        return (<div>JSX input: <input type='text' value='入力欄' /></div>);
    }
});

ReactDOM.render(
    <TextInput />,
    document.getElementById('content')
);

これで、htmlとjsxのフォームを比較してみる。

  • jsxのほうは、編集ができない。value=で指定したものは、valueを更新しない限り編集ができないらしい。JSXで、htmlのvalue(初期値)のようにしたい場合は、defaultValueを使うらしい。
  • ただ、valueを指定していないinput要素はデータの受け渡しができないので意味がない。
  • こういう時は、コンソールのerrorを見てみるといいらしい。Failed form propType: You provided avalueprop to a form field without anonChangehandler.とのことなので、編集した時の処理ように、onChangeを使うといいらしい。
var TextInput = React.createClass({

# Stateを設定する。ここでは、dispTextというstateの初期値を設定している。
    getInitialState: function(){
        return {dispText: '入力欄'};
    },

# handleInputは独自のメソッド。JSXのinputが変更された時に呼び出される。this.setStateメソッドで、event.target.valueをdispText stateに代入するように設定してある。
    handleInput: function(event){
        this.setState({dispText: event.target.value});
        console.log(this.state.dispText);
    },

# value=dispTextで、onChangeした時に、handleInputが呼び出されるようになっている。
    render: function(){
        return (<div>JSX InputText: <input
            type='text'
            value={this.state.dispText}
            onChange={this.handleInput}
        />
        </div>);
    }
});

ReactDOM.render(
    <TextInput />,
    document.getElementById('content')
);

ちょっとずつ難しくなってきたな。

type属性とchecked属性でラジオボタンを実現する

var RadioButton = React.createClass({
    render: function() {
        return (<div>どれか1つを選んでください。:
            <div>
                <input
                    type="radio"
                    name="三択"
                    value="first"
                    checked
                />最初の選択肢
            </div>
            <div>
                <input
                    type="radio"
                    name="三択"
                    value="second"
                />次の選択肢
            </div>
            <div>
                <input
                    type="radio"
                    name="三択"
                    value="third"
                />最後の選択肢
            </div>
        </div>);
    }
});

ReactDOM.render(
    <RadioButton />,
    document.getElementById('content')
)

これだと、onChangeがなくて編集ができないので、テキストボックスの時と同じように修正する。

var RadioButton = React.createClass({
# selectionというStateの初期値をセットする。
    getInitialState: function(){
        return {selection: 'first'};
    },
# onChangeで呼び出されるメソッドをセットする。Stateを変更するという内容。
    handleChange: function(event){
        console.log(event.target.value);
        this.setState({selection: event.target.value});
    },

# renderメソッドをセットする。checkedの属性に、合致するvalueの時だけcheckedがつくようにセットする。
    render: function() {
        return (<div>どれか1つを選んでください。:
            <div>
                <input
                    type="radio"
                    value="first"
                    checked={this.state.selection ==='first'}
                    onChange={this.handleChange}
                />最初の選択肢
            </div>
            <div>
                <input
                    type="radio"
                    value="second"
                    checked={this.state.selection ==='second'}
                    onChange={this.handleChange}
                />次の選択肢
            </div>
            <div>
                <input
                    type="radio"
                    value="third"
                    checked={this.state.selection ==='third'}
                    onChange={this.handleChange}
                />最後の選択肢
            </div>
        </div>);
    }
});

ReactDOM.render(
    <RadioButton />,
    document.getElementById('content')
)

type属性で複数選択可能なチェックボックスを作成する。

var CheckBox = React.createClass({
# Stateの初期値を配列でセットする。
    getInitialState: function(){
        return {selection: ['first']};
    },
# selection stateのコピーを作成する
# valueのselection state内の配列での位置をpositionに代入する。
    handleChange: function(event){
        var selection = this.state.selection
        var position = selection.indexOf(event.target.value);
# onChangeされた時に、対象がチェックされていたら、そのvalueをselection state配列にpushする。
        if (event.target.checked){
            selection.push(event.target.value);
# それ以外の時(チェックが外された場合)は、spliceで、要素を削除する。
        } else {
            selection.splice(position, 1);
        }
# 上記の処理をした後に、再度selectionをstateにセットする。
        this.setState({selection: selection});
        console.log(event.target.value);
    },

# render メソッドをセットする。
    render: function() {
        return (<div>複数回答可です。:
            <div>
                <input
                    type="checkbox"
                    value="first"
# indexOfは、含まれている場合は、positionの位置を返して、含まれてない場合は、-1を返すのか?
                    checked={this.state.selection.indexOf('first') !== -1}
                    onChange={this.handleChange}
                />最初の選択肢
            </div>
            <div>
                <input
                    type="checkbox"
                    value="second"
                    checked={this.state.selection.indexOf('second') !== -1}
                    onChange={this.handleChange}
                />次の選択肢
            </div>
            <div>
                <input
                    type="checkbox"
                    value="third"
                    checked={this.state.selection.indexOf('third') !== -1}
                    onChange={this.handleChange}
                />最後の選択肢
            </div>
        </div>);
    }
});

# 上記でセットした(上書きした?)renderメソッドで、html要素を返す。
ReactDOM.render(
    <CheckBox />,
    document.getElementById('content')
)

うーん、ちょっと冗長な感じがするなぁ、まあたぶんフォームを直接reactで作ることはないと思うからいいか(^ ^;)

プロパティによって選択状態の初期値を設定する

var CheckBox = React.createClass({
    getInitialState: function(){
// ここで、props.selectionを初期値に代入する
        return {selection: this.props.selection};
    },

// 中略

ReactDOM.render(
// ここで、propsの初期値をセットする。
    <CheckBox selection={['second','third']} />,
    document.getElementById('content')
)

value属性でセレクトボックスを選択可能にする。

1つだけ選択する場合

var SingleSelection = React.createClass({
# Stateの初期化を、プロパティを代入してセットする。
    getInitialState: function(){
        return {selection: this.props.selection};
    },
# changeした時に呼び出すメソッドを設定
    handleChange: function(event){
        console.log(event.target.value);
        this.setState({selection: event.target.value});
    },
# render時のメソッドを設定
    render: function() {
        return (<div>どれか1つを選んでください。:
                <select
                    onChange={this.handleChange}
                    multiple={false}
                    value={this.state.selection}>
                <option value="first">最初の選択肢</option>
                <option value="second">次の選択肢</option>
                <option value="third">最後の選択肢</option>
                </select>
        </div>);
    }
});

# renderメソッドで、html要素を返す
ReactDOM.render(
    <SingleSelection selection={'third'} />,
    document.getElementById('content')
)

複数選択可能にする場合

var SingleSelection = React.createClass({
# Stateの初期化メソッド、初期値には、プロパティ値をセットする。
    getInitialState: function(){
        return {selection: this.props.selection};
    },
# onChangeの時によびだされるメソッドの設定
    handleChange: function(event){
# selectionに、selection stateを代入してコピーを作成する、対象のpositionもゲットしておく。
        var selection = this.state.selection;
        var position = selection.indexOf(event.target.value);
        if (position === -1) {
            selection.push(event.target.value);
        }else{
            selection.splice(position, 1);
        }
        this.setState({selection: selection});
        console.log(event.target.value);
    },
# renderメソッドをセットする。
    render: function() {
        return (<div>複数回答可能です。:
            <select
                onChange={this.handleChange}
                multiple={true}
                value={this.state.selection}
                size="3">
                <option value="first">最初の選択肢</option>
                <option value="second">次の選択肢</option>
                <option value="third">最後の選択肢</option>
            </select>
        </div>);
    }
});

# カスタムコンポーネントをrenderメソッドで、html要素として返す。
ReactDOM.render(
    <SingleSelection selection={['first','third']} />,
    document.getElementById('content')
)