ReactJS - RefsとDOM

こんにちは、未来のReact開発者さんたち!今日は、Reactアプリケーション内のDOM要素と直接やりとりするための興味深いトピックに取り組んでみましょう。しっかりと準備をして、RefsとDOMの世界に飛び込みましょう!

ReactJS - Refs and the DOM

Refsとは?

本題に入る前に、Refsが何かを理解しましょう。Reactでは、「Ref」は「reference」の略です。特定の要素に名前タグを付けるようなもので、後で簡単に見つけられるようにします。大きなパーティーで、親友を追踪したいと考えたとき、特別な帽子をかぶせたり、ユニークな名前タグを付けたりするかもしれません。这正是ReactでRefsが行うことです - 特定の要素を追踪する手助けをしてくれます。

Refsが必要な理由

「なぜ、通常のJavaScriptを使って要素を選択できないの?」と疑うかもしれません。Reactでは、UIを更新するための効率的な方法を持っているため、直接DOMを操作することを避けます。しかし、Reactの宣言的パラダイムから一歩外れて、DOM要素を直接操作する必要がある時があります。その際にRefsが役立ちます!

createRef()を使ってRefsを作成する

まず、ReactでRefsを作成する方法を見てみましょう。createRef()メソッドを使います。

createRefメソッドのシグネチャ

createRef()のシグネチャは非常にシンプルです:

React.createRef()

それだけです!パラメータはありません。返されるのは、単一のプロパティ「current」を持つプレーンなオブジェクトで、初期値はnullです。

例を見てみましょう:

class MyComponent extends React.Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
}

render() {
return <div ref={this.myRef} />;
}
}

この例では、コンストラクタでRefsを作成し、this.myRefに割り当てます。そして、renderメソッドでこのRefsをdiv要素にref属性を使ってアタッチします。

Refの適用

Refsを作成したので、それを使ってみましょう。Refsを適用する方法はいくつかあります:

1. DOM要素へのRefs

最も一般的な使い方として、RefsをDOM要素に適用します:

class AutoFocusInput extends React.Component {
constructor(props) {
super(props);
this.inputRef = React.createRef();
}

componentDidMount() {
this.inputRef.current.focus();
}

render() {
return <input ref={this.inputRef} />;
}
}

この例では、インプット要素に対してRefsを作成し、コンポーネントがマウントされた後にインプットに自動でフォーカスを当てます。Refsのcurrentプロパティを使うことで、実際のDOMノードにアクセスできます。

2. クラスコンポーネントへのRefs

クラスコンポーネントにもRefsを使うことができます:

class AutoScrollingList extends React.Component {
constructor(props) {
super(props);
this.listRef = React.createRef();
}

componentDidUpdate() {
const node = this.listRef.current;
node.scrollToItem(0);
}

render() {
return <MyListComponent ref={this.listRef} />;
}
}

この場合、this.listRef.currentMyListComponentクラスのインスタンスを指します。

3. 関数コンポーネントへのRefs

関数コンポーネントには直接Refsを設定できませんが、forwardRef関数を使うことでRefsを渡すことができます:

const FancyButton = React.forwardRef((props, ref) => (
<button ref={ref} className="FancyButton">
{props.children}
</button>
));

class MyComponent extends React.Component {
constructor(props) {
super(props);
this.buttonRef = React.createRef();
}

render() {
return <FancyButton ref={this.buttonRef}>クリックしてね!</FancyButton>;
}
}

この例では、FancyButtonforwardRefを使ってRefsを実際のボタン要素に渡します。

createRefのユースケース

Refsの作成と適用方法を理解したので、いくつかの一般的なユースケースを見てみましょう:

1. フォーカス、テキスト選択、メディア再生の管理

class TextInput extends React.Component {
constructor(props) {
super(props);
this.inputRef = React.createRef();
}

focusTextInput = () => {
this.inputRef.current.focus();
}

render() {
return (
<div>
<input type="text" ref={this.inputRef} />
<button onClick={this.focusTextInput}>インプットにフォーカス</button>
</div>
);
}
}

このコンポーネントは、ボタンをクリックするとインプットにフォーカスを当てることができます。

2. 命令型アニメーションのトリガー

class Animator extends React.Component {
constructor(props) {
super(props);
this.elementRef = React.createRef();
}

animate = () => {
this.elementRef.current.classList.add('animated');
}

render() {
return (
<div>
<div ref={this.elementRef}>アニメーションしてね!</div>
<button onClick={this.animate}>アニメーション開始</button>
</div>
);
}
}

ここでは、Refsを使ってCSSクラスを要素に追加し、アニメーションをトリガーします。

3. 第三パーティのDOMライブラリとの統合

class MapComponent extends React.Component {
constructor(props) {
super(props);
this.mapRef = React.createRef();
}

componentDidMount() {
const mapLibrary = new FancyMapLibrary();
mapLibrary.createMap(this.mapRef.current);
}

render() {
return <div ref={this.mapRef} style={{width: '100%', height: '400px'}} />;
}
}

この例では、Refsを使って第三パーティのマップライブラリにDOMノードを渡し、マップをレンダリングします。

結論

Refsは、必要なときに宣言的パラダイムから一歩外れて、DOMノードやReact要素に直接アクセスする強力なツールです。しかし、Refsを使う際には慎重に考えましょう。大多数のケースでは、Reactの宣言的APIで十分にできますが、追加の制御が必要なときにはRefsが役立ちます!

忘れないでください、力には責任が伴います。Refsを賢く使うことで、Reactアプリケーションは感謝してくれるでしょう!

以下は、私たちが話し合ったメソッドの簡単な参照表です:

メソッド 説明
React.createRef() Refオブジェクトを作成する this.myRef = React.createRef();
ref属性 RefをReact要素にアタッチする <div ref={this.myRef} />
forwardRef 関数コンポーネントにRefsを渡す const FancyButton = React.forwardRef((props, ref) => ...)

ハッピーコーディング、そしてRefsが常に「current」であることを祈っています!

Credits: Image by storyset