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
要素が格納される。