JavaScript
React
react-hooks
72
どのような問題がありますか?

この記事は最終更新日から1年以上が経過しています。

Organization

【React hooks】意外と知らないrefの使い方

Reactでコンポーネントから子コンポーネントや要素などを操作するときに便利なrefだが、
意外に調べても使い方が出てこなかったので、様々な利用シーンに合わせて使い道をまとめてみた。

DOMにアクセス

import React, {
    useRef, useEffect
} from 'react';

const Component = () => {
    const el = useRef(null);

    useEffect(() => {
        console.log(el.current);
    }, []);

    return (
        <div ref={el}>DOM</div>
    );
};

export default Component;

el.currentからdiv要素にアクセスできるようになる。
divの幅、高さを取ってきたり、D3などでDOMにグラフを描画する際に使用する。

子コンポーネントのインスタンスにアクセス

import React, {
    useRef, useEffect
} from 'react';

class Child extends React.Component {
    someFunc = () => {
        return 'sample';
    }

    render() {
        return <div> </div>;
    }
}

const Component = () => {
    const ins = useRef(null);

    useEffect(() => {
        console.log(ins.current);
    }, []);

    return (
        <Child ref={ins} />
    );
};

export default Component;

ins.currentから子コンポーネントChildのインスタンスにアクセスができる。
例えば、ins.current.someFunc()で子コンポーネントの関数を実行することができる。
※関数コンポーネント (functional component)ではインスタンスが作成されないため利用できない。

refのフォワーディング(forwardRef)

import React, {
    useRef, useEffect
} from 'react';

const Child = React.forwardRef((props, ref) => {
    return (
        <div ref={ref}>DOM</div>
    );
});

const Component = () => {
    const el = useRef(null);

    useEffect(() => {
        console.log(el.current);
    }, []);

    return (
        <Child ref={el} />
    );
};

export default Component;

el.currentで親コンポーネントから子コンポーネントを介してdiv要素にアクセスすることができる。
HOC(Higher-Order Component)などでコンポーネントを関数で囲む際などに、refをそのまま受け渡すという目的で利用する。
アプリケーションが複雑になればなるほど重宝する機能。

複数refs

import React, {
    useRef, useEffect
} from 'react';

const data = [0, 1, 2];

const Component = () => {
    const els = useRef([]);
    data.forEach((_, i) => {
        els.current[i] = React.createRef();
    });

    useEffect(() => {
        console.log(els.current);
    }, []);

    return (
        <div>
            {
                data.map((n, i) => {
                    return (
                        <div key={n} ref={els.current[i]} >{n}</div>
                    );
                })
            }
        </div>
    );
};

export default Component;

els.currentにはdiv要素の配列が格納されるようになる。
複数の要素にアクセスが必要なシーンで利用する。

応用編(複数Refs × 複数Refs)

import React, {
    useRef, useEffect
} from 'react';

const data = [0, 1, 2];

const ChildComponent = React.forwardRef(({ val1 }, ref) => {
    const els = useRef([]);
    data.forEach((_, i) => {
        els.current[i] = React.createRef();
    });

    useEffect(() => {
        ref.current = els.current;
        return () => {
            ref.current = null;
        };
    }, []);

    return (
        <div>
            {
                data.map((val2, i) => {
                    return (
                        <div key={val2} ref={els.current[i]}>
                            {val1}
                            -
                            {val2}
                        </div>
                    );
                })
            }
        </div>
    );
});

const Component = () => {
    const els = useRef([]);
    data.forEach((_, i) => {
        els.current[i] = React.createRef();
    });

    useEffect(() => {
        console.log(els.current);
    }, []);

    return (
        <div>
            {
                data.map((val1, i) => {
                    return (
                        <ChildComponent key={val1} val1={val1} ref={els.current[i]} />
                    );
                })
            }
        </div>
    );
};

export default Component;

els.currentには[[div,div,div], [div,div,div], [div,div,div]]みたいな感じで配列の配列でdiv要素が格納される。

ユーザー登録して、Qiitaをもっと便利に使ってみませんか。
  1. あなたにマッチした記事をお届けします
    ユーザーやタグをフォローすることで、あなたが興味を持つ技術分野の情報をまとめてキャッチアップできます
  2. 便利な情報をあとで効率的に読み返せます
    気に入った記事を「ストック」することで、あとからすぐに検索できます
tonio0720
valuesccg
「インターネット行動ログ分析サービス」など、デジタルマーケティング領域での新たな価値創造を通し、各企業の成長支援を行っています。エンジニア募集中。
この記事は以下の記事からリンクされています
kome13jReactでscrollRevealを使用するからリンク

コメント

(編集済み)
リンクをコピー
このコメントを報告
const els = useRef(data.map(() => createRef()));

はどうでしょう??

0
どのような問題がありますか?
あなたもコメントしてみませんか :)
ユーザー登録
すでにアカウントを持っている方はログイン
72
どのような問題がありますか?
ユーザー登録して、Qiitaをもっと便利に使ってみませんか

この機能を利用するにはログインする必要があります。ログインするとさらに下記の機能が使えます。

  1. ユーザーやタグのフォロー機能であなたにマッチした記事をお届け
  2. ストック機能で便利な情報を後から効率的に読み返せる
ユーザー登録ログイン
ストックするカテゴリー