我有一个SideNav组件,其中包含动态创建的链接,这些链接需要滚动到相邻html表(InfoTable)中的相应头。我尝试了多种不同的方法来完成此操作,但无济于事。
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上动态创建的引用,并将这些引用设置为DOM节点InfoTable中的每个标头。从那里,我将一个函数传递给SideNav,该函数可以访问Parent中的引用以滚动到标题。
答案 0 :(得分:21)
我知道有一个已经被接受的答案,尽管我发现@ nicholas-haley的解决方案是可以接受的。
我认为一种更好的解决方法是使用内置的useImperativeHandle
挂钩。
重要提示:React Hooks Api自
开始可用
- react@16.8.0及更高版本
- react-native@0.59.0及更高版本
一起使用
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} ... />
....
)
}
答案 1 :(得分:4)
我遇到过类似的情况,我需要将多个引用转发给我的Parent组件的子代。
我仍然没有找到一个好的解决方案,但是您可以尝试将ref作为对象传递,并在forwardRef
回调中进行破坏:
// Parent
ref={{
ref1: this.ref1,
ref2: this.ref2
}}
// Child
export default React.forwardRef((props, ref) => {
const { ref1, ref2 } = ref;
return (
<Child
{...props}
ref1={ref1}
ref2={ref2}
/>
);
});
我不太喜欢此处的命名(我更喜欢将ref
称为refs
),但这在您遇到麻烦时可以使用。
答案 2 :(得分:1)
我实际上只是从react-hook-form中挑选出来的,但是他们提供了一种共享引用并立即分配多个引用的好方法:
<input name="firstName" ref={(e) => {
register(e) // use ref for register function
firstNameRef.current = e // and you can still assign to ref
}} />