如果我有类似
的话<Parent>
<Child1 />
<Child2 />
<Child3 />
</Parent>
我希望从Child2
访问refs="child2refs"
,我该怎么办?
答案 0 :(得分:54)
如果无法避免,则从React docs中提取的建议模式为:
import React, { Component } from 'react';
const Child = ({ setRef }) => <input type="text" ref={setRef} />;
class Parent extends Component {
constructor(props) {
super(props);
this.setRef = this.setRef.bind(this);
}
componentDidMount() {
// Calling a function on the Child DOM element
this.childRef.focus();
}
setRef(input) {
this.childRef = input;
}
render() {
return <Child setRef={this.setRef} />
}
}
父将功能转发为父 this
的支柱。当React调用孩子的 ref
道具setRef
时,它会将孩子 ref
分配给父母的 childRef
财产。
参考转发是一项选择加入功能,可让某些组件接收他们收到的参考,并将其进一步向下传递(换句话说,“转发”给孩子。
我们创建组件,用ref
转发他们的React.forwardRef
。
返回的组件 ref prop必须与返回类型React.createRef
的类型相同。每当React挂载DOM节点时,使用current
创建的ref
的属性React.createRef
将指向底层DOM节点。
import React from "react";
const LibraryButton = React.forwardRef((props, ref) => (
<button ref={ref} {...props}>
FancyButton
</button>
));
class AutoFocus extends React.Component {
constructor(props) {
super(props);
this.childRef = React.createRef();
this.onClick = this.onClick.bind(this);
}
componentDidMount() {
this.childRef.current.focus();
}
onClick() {
console.log("fancy!");
}
render() {
return <LibraryButton onClick={this.onClick} ref={this.childRef} />;
}
}
已创建的组件正在将其ref
转发给子节点。
function logProps(Component) {
class LogProps extends React.Component {
componentDidUpdate(prevProps) {
console.log('old props:', prevProps);
console.log('new props:', this.props);
}
render() {
const {forwardedRef, ...rest} = this.props;
// Assign the custom prop "forwardedRef" as a ref
return <Component ref={forwardedRef} {...rest} />;
}
}
// Note the second param "ref" provided by React.forwardRef.
// We can pass it along to LogProps as a regular prop, e.g. "forwardedRef"
// And it can then be attached to the Component.
return React.forwardRef((props, ref) => {
return <LogProps {...props} forwardedRef={ref} />;
});
}
请参阅React docs中的Forwarding Refs。
答案 1 :(得分:17)
/*
* Child component
*/
class Child extends React.Component {
render() {
return (
<div id="child">
<h1 ref={(node) => { this.heading = node; }}>
Child
</h1>
</div>
);
}
}
/*
* Parent component
*/
class Parent extends React.Component {
componentDidMount() {
// Access child component refs via parent component instance like this
console.log(this.child.heading.getDOMNode());
}
render() {
return (
<div>
<Child
ref={(node) => { this.child = node; }}
/>
</div>
);
}
}
答案 2 :(得分:15)
首先使用this.props.children
访问孩子,然后每个孩子都会将ref
作为属性。
答案 3 :(得分:2)
使用Ref转发,您可以将ref从父级传递到子级。
const FancyButton = React.forwardRef((props, ref) => (
<button ref={ref} className="FancyButton">
{props.children}
</button>
));
// You can now get a ref directly to the DOM button:
const ref = React.createRef();
<FancyButton ref={ref}>Click me!</FancyButton>;
注意 仅当使用React.forwardRef调用定义组件时,第二个ref参数才存在。常规函数或类组件不会接收ref参数,并且ref在props中也不可用。
引用转发不限于DOM组件。您也可以将引用转发到类组件实例。
参考:React文档。
答案 4 :(得分:2)
以下是我解决动态组件问题的方法:
在父组件上,动态创建对子组件的引用,例如:
class Form extends Component {
fieldRefs: [];
// dynamically create the child references on mount/init
componentWillMount = () => {
this.fieldRefs = [];
for(let f of this.props.children) {
if (f && f.type.name == 'FormField') {
f.ref = createRef();
this.fieldRefs.push(f);
}
}
}
// used later to retrieve values of the dynamic children refs
public getFields = () => {
let data = {};
for(let r of this.fieldRefs) {
let f = r.ref.current;
data[f.props.id] = f.field.current.value;
}
return data;
}
}
子组件(即
class FormField extends Component {
field = createRef();
render() {
return(
<input ref={this.field} type={type} />
);
}
}
然后在您的主页,“父级的父级”组件中,您可以从引用中获取字段值:
class Page extends Component {
form = createRef();
onSubmit = () => {
let fields = this.form.current.getFields();
}
render() {
return (
<Form ref={this.form}>
<FormField id="email" type="email" autoComplete="email" label="E-mail" />
<FormField id="password" type="password" autoComplete="password" label="Password" />
<div class="button" onClick={this.onSubmit}>Submit</div>
</Form>
);
}
}
我实现这个是因为我想从一个主要的
组件中封装所有通用的表单功能,并且能够设置主要的客户端/页面组件并设置它自己的内部组件样式的唯一方法是使用 child组件(即父 中的所以,虽然有些人可能认为这是一种黑客行为,但它就像 React 试图阻止来自任何父级的实际“ref”一样,我认为这是一个荒谬的设计,但他们希望将其合理化。
答案 5 :(得分:1)
这里是一个示例,该示例将重点介绍使用refs(在React 16.8.6中测试)的输入:
子组件:
class Child extends React.Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
}
render() {
return (<input type="text" ref={this.myRef} />);
}
}
内部包含“子级”组件的“父级”组件:
class Parent extends React.Component {
constructor(props) {
super(props);
this.childRef = React.createRef();
}
componentDidMount() {
this.childRef.current.myRef.current.focus();
}
render() {
return <Child ref={this.childRef} />;
}
}
ReactDOM.render(
<Parent />,
document.getElementById('container')
);
具有this.props.children的Parent组件:
class Parent extends React.Component {
constructor(props) {
super(props);
this.childRef = React.createRef();
}
componentDidMount() {
this.childRef.current.myRef.current.focus();
}
render() {
const ChildComponentWithRef = React.forwardRef((props, ref) =>
React.cloneElement(this.props.children, {
...props,
ref
})
);
return <ChildComponentWithRef ref={this.childRef} />
}
}
ReactDOM.render(
<Parent>
<Child />
</Parent>,
document.getElementById('container')
);
答案 6 :(得分:0)
我认为本指南对其进行了很好的解释https://github.com/yannickcr/eslint-plugin-react/issues/678
class Field extends Component {
const { inputRef } = this.props;
render() {
return (
<input type="text" ref={inputRef} />
)
}
}
class MyComponent extends Component {
componentDidMount() {
this.inputNode.focus();
}
render() {
return (
<div>
Hello, <Field inputRef={node => this.inputNode = node} />
</div>
)
}
}