dackdive's blog

新米webエンジニアによる技術ブログ。JavaScript(React), Salesforce, Python など

Material-UIでrefを使う

メモ。
以下のようなコンポーネント<input type="text"> 項目を Material-UI の TextField に置き換えようと思ったが
ref で参照しているのをそのまま TextField でも使えるのか迷った。

import React, { PropTypes } from 'react';

export default class AddTodoForm extends React.Component {
  handleSubmit(e) {
    e.preventDefault();
    const node = this.refs.input;
    const text = node.value.trim();
    if (!text) {
      return;
    }
    this.props.onSubmit(text);
    node.value = '';
  }

  render() {
    return (
      <div>
        <form onSubmit={(e) => this.handleSubmit(e)}>
          <input type="text" ref="input" />
          <button type="submit">
            Add Todo
          </button>
        </form>
      </div>
    );
  }
}

AddTodoForm.propTypes = {
  onSubmit: PropTypes.func.isRequired,
};


先に結論

値の参照だけしたいときは

this.refs.xxx.getValue()

とし、DOM Node を取得する場合は

this.refs.xxx.getInputNode()

を使う。

両方ともドキュメントには載っておらず、前者は以下の Stack Overflow から
javascript - How get data from material-ui TextField, DropDownMenu components? - Stack Overflow

後者は以下のようにブラウザの開発者コンソールから無理やり見つけた。

f:id:dackdive:20161123195515p:plain


string ref を使う場合

 import React, { PropTypes } from 'react';
+import RaisedButton from 'material-ui/RaisedButton';
+import TextField from 'material-ui/TextField';

 export default class AddTodoForm extends React.Component {
   handleSubmit(e) {
     e.preventDefault();
-    const node = this.refs.input;
+    const node = this.refs.input.getInputNode();
     const text = node.value.trim();
     if (!text) {
       return;
@@ -16,10 +18,8 @@ export default class AddTodoForm extends React.Component {
     return (
       <div>
         <form onSubmit={(e) => this.handleSubmit(e)}>
-          <input ref="input" />
-          <button type="submit">
-            Add Todo
-          </button>
+          <TextField id="todo-title" ref="input" />
+          <RaisedButton label="Add Todo" onTouchTap={(e) => this.handleSubmit(e)} />
         </form>
       </div>
     );
diff --git a/src/containers/App.js b/src/containers/App.js
index 8068f95..4ee5acf 100644
--- a/src/containers/App.js
+++ b/src/containers/App.js
@@ -18,4 +18,3 @@ export default class App extends React.Component {
     );
   }
 }


arrow function による ref を使う場合

上述した string ref は現在推奨されていないらしい
(参考:http://reactjs.cn/react/docs/more-about-refs.html#the-ref-string-attribute
ので、arrow 関数を使った場合の書き方も載せておく。

https://facebook.github.io/react/docs/refs-and-the-dom.html

 import React, { PropTypes } from 'react';
+import RaisedButton from 'material-ui/RaisedButton';
+import TextField from 'material-ui/TextField';

 export default class AddTodoForm extends React.Component {
   handleSubmit(e) {
     e.preventDefault();
-    const node = this.refs.input;
+    const node = this.input.getInputNode();
     const text = node.value.trim();
     if (!text) {
       return;
@@ -16,10 +18,8 @@ export default class AddTodoForm extends React.Component {
     return (
       <div>
         <form onSubmit={(e) => this.handleSubmit(e)}>
-          <input ref="input" />
-          <button type="submit">
-            Add Todo
-          </button>
+          <TextField id="todo-title" ref={(input) => this.input = input} />
+          <RaisedButton label="Add Todo" onTouchTap={(e) => this.handleSubmit(e)} />
         </form>
       </div>
     );
     );
   }
 }