Material-UIのTextFieldでrefを使う

TextFieldでrefを使う

Material-UI導入時、inputをTextFieldに置き換える時に、多くの属性は<input><TextField>に置き換えた際そのままでよいのですが、refはそのままにすると動きません。refinputRefに変更する必要があります。

変更前

const AddTodo = ({dispatch}) => {
  let input;

  // 略
  return (
    <input
      ref={node => {
        input = node
      }}
    />
  )
}

変更後

import TextField from '@material-ui/core/TextField'

class AddTodo extends React.Component {
  render() {
    return (
      <TextField
        inputRef={node => {
          this.inputElement = node
        }}
      />
    )
  }
}

<TextField><input>そのものではないので、TextFieldにrefを指定しても動きません。代わりに、inputRefプロパティを渡して、(TextFieldから子孫コンポーネンントにバケツリレーして、)<input ref={props.inputRef}>としてrefを設定します。

同様に、inputにプロパティ(readonlyやstepなど)を渡す場合にも、inputPropsにオブジェクトを渡します。

関数コンポーネントからクラスに変更した理由と、node => { this.inputElement = node}に変更した理由はこちらの記事を参照してください。

yucatio.hatenablog.com

refの使用

inputRefの使用については、 React公式ページの例がわかりやすいと思います。

Callback Refs

You can pass callback refs between components like you can with object refs that were created with React.createRef().

function CustomTextInput(props) {
  return (
    <div>
      <input ref={props.inputRef} />
    </div>
  );
}

class Parent extends React.Component {
  render() {
    return (
      <CustomTextInput
        inputRef={el => this.inputElement = el}
      />
    );
  }
}

In the example above, Parent passes its ref callback as an inputRef prop to the CustomTextInput, and the CustomTextInput passes the same function as a special ref attribute to the <input>. As a result, this.inputElement in Parent will be set to the DOM node corresponding to the <input> element in the CustomTextInput.

Refs and the DOM – React

"React.createdRef()でrefを作成したのと同じように、コンポーネント間でコールバックrefを渡すことができます。

上記の例では、親コンポーネントはCustomTextInputにrefコールバックをinputRefプロパティとして渡し、CustomTextInputはinputRefで受け取った関数を<input>のref属性に設定しています。そのため、親コンポーネントのthis.inputElementはCustomTextInputの<input>のDOMノードが設定されることになります。"

あとがき

refが何であるかきちんと理解しないままinputをTextFieldに置き換えていたので、ハマりました。公式ドキュメント(Refs and the DOM – React) を読んでrefの理解が深まりました。

バージョン

  • @material-ui/core: 3.4.0