隣接する HTML テーブル (InfoTable) 内の対応するヘッダーまでスクロールする必要がある、動的に作成されたリンクを含む SideNav コンポーネントがあります。これを実現するためにさまざまな方法を試しましたが、うまくいきませんでした。
export default class Parent extends Component {
state = {
categories: [],
}
scrollToHeader = (tableRefString) => {
// Function to pass to SideNav to access refs in InfoTable
this[tableRefString].scrollIntoView({ block: 'start' });
}
render() {
return (
<div>
<SideNav
categories={this.state.categories}
scrollToHeader={this.scrollToHeader} />
<InfoTable
categories={this.state.categories} />
</div>
);
}
}
export default class InfoTable extends Component {
render() {
return (
<div>
<table>
<tbody>
{this.props.categories.map(category => (
<>
// Forward the ref through InfoTableHeader to be set on the parent DOM node of each InfoTableHeader
<InfoTableHeader />
{category.inputs.map(input => <InfoTableRow />)}
</>
))}
</tbody>
</table>
</div>
);
}
}
SideNav のリンクをクリックして InfoTable の対応するヘッダーまでスクロールするには、カテゴリ配列内の名前に基づいて Parent に動的に作成される参照を転送し、これらの参照を InfoTable の各ヘッダーの DOM ノードに設定する必要があると思います。そこから、ヘッダーまでスクロールするために Parent の参照にアクセスできる関数を SideNav に渡します。
- 複数の参照を InfoTable コンポーネントに一度に転送するにはどうすればよいですか?
- 私がやろうとしていることをよりきれいに実現する方法はありますか? React.findDOMNode() を調べましたが、refs の方が良い選択肢のようです。
ベストアンサー1
すでに受け入れられている回答があることは承知していますが、@nicholas-haley の解決策は受け入れられると思います。組み込みuseImperativeHandle
フックを使用する方がよいと思います。
重要: React Hooks APIは、
useImperativeHandle
refを使用するときに親コンポーネントに公開されるインスタンス値をカスタマイズします。いつものように、refを使用する命令型コードはほとんどの場合避けるべきです。useImperativeHandleは`forwardRefと一緒に使用する必要があります。
この注記の後に次の例が続きます。
function FancyInput(props, ref) {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
}
}));
return <input ref={inputRef} ... />;
}
FancyInput = forwardRef(FancyInput);
したがって、私の意見では、よりクリーンな解決策は必要な参照をuseImperativeHandle
フックを通じて委譲する。
この方法では、特別な ref 構文は必要なく、コンポーネントは FatherRef の特定の型を返すだけです。例:
// LabelInput.js
function LabelInput(props, ref) {
const labelRef = useRef();
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
},
get input() {
return inputRef.current;
},
get label() {
return labelRef.current;
},
// ... whatever else one may need
}));
return (
<div>
<label ref={labelRef} ... />
<input ref={inputRef} ... />;
</div>
)
}
LabelInput = forwardRef(LabelInput);
function MyScreen() {
const labelInputRef = useRef();
const onClick = useCallback(
() => {
// labelInputRef.current.focus(); // works
// labelInputRef.current.input.focus(); // works
// ... etc
},
[]
);
return (
...
<LabelInput ref={labelInputRef} ... />
....
)
}
編集:古いドキュメントもこのユースケースに完全に関連していますが、ここに新しいリンクもあります。https://react.dev/reference/react/useImperativeHandle#独自の命令型メソッドを公開する