我有两个组成部分:
父组件
子组件
我试图从Parent调用Child的方法,我尝试了这种方式,但不能得到一个结果:
class Parent extends Component {
render() {
return (
<Child>
<button onClick={Child.getAlert()}>Click</button>
</Child>
);
}
}
class Child extends Component {
getAlert() {
alert('clicked');
}
render() {
return (
<h1 ref="hello">Hello</h1>
);
}
}
是否有一种方法从父调用子方法?
注意:子组件和父组件在两个不同的文件中。
我尝试使用createRef或useRef。它们都返回null。
其次,这个答案提出通过一个道具来设置一个在我看来最合理的函数。但如果子组件用于多个地方,则应该将额外的道具添加到其他地方。此外,如果您想在孙辈中调用一个方法,这个方法可能太啰嗦或太冗长。
所以我用一种非常原始的方式创建了我自己的函数存储。
下面是functionStore.js文件
const fns = {};
export function setFn(componentName, fnName, fn) {
if (fns[componentName]) {
fns[componentName][fnName] = fn;
} else {
fns[componentName] = { fnName: fn };
}
}
export function callFn(componentName, fnName) {
fns[componentName][fnName]();
}
我只是设置了需要从任何组件调用的函数。
import { setFn } from "./functionStore";
export class AComponent extends React.Component {
componentDidMount() {
setFn("AComponent", "aFunc", this.aFunc);
}
aFunc = () => { console.log("aFunc is called!"); };
}
然后我从其他组件调用它
import { callFn } from "./functionStore";
export class BComponent extends React.Component {
// just call the function
bFunc = () => {
callFn("AComponent", "aFunc");
};
}
一个缺点是要调用的函数应该是无参数的。但这也可能以某种方式解决。目前,我不需要传递参数。
这里有个虫子?注意:
我同意rossipedia的解决方案使用forwardRef, useRef, useImperativeHandle
网上有一些错误的信息说refs只能从React类组件创建,但如果你使用上面提到的钩子,你确实可以使用函数组件。注意,只有在我将文件更改为在导出组件时不使用withRouter()后,钩子才对我有效。例如,从
export default withRouter(TableConfig);
取而代之的是
export default TableConfig;
In hindsight the withRouter() is not needed for such a component anyway, but usually it doesn't hurt anything having it in. My use case is that I created a component to create a Table to handle the viewing and editing of config values, and I wanted to be able to tell this Child component to reset it's state values whenever the Parent form's Reset button was hit. UseRef() wouldn't properly get the ref or ref.current (kept on getting null) until I removed withRouter() from the file containing my child component TableConfig
我们可以用另一种方式使用refs,如-
我们将创建一个父元素,它将呈现一个<Child/>组件。如您所见,对于将要呈现的组件,您需要添加ref属性并为其提供名称。
然后,位于父类中的triggerChildAlert函数将访问this context的refs属性(当triggerChildAlert函数被触发时,它将访问子引用,并且它将具有子元素的所有函数)。
class Parent extends React.Component {
triggerChildAlert(){
this.refs.child.callChildMethod();
// to get child parent returned value-
// this.value = this.refs.child.callChildMethod();
// alert('Returned value- '+this.value);
}
render() {
return (
<div>
{/* Note that you need to give a value to the ref parameter, in this case child*/}
<Child ref="child" />
<button onClick={this.triggerChildAlert}>Click</button>
</div>
);
}
}
现在,子组件,就像之前理论上设计的那样,看起来像:
class Child extends React.Component {
callChildMethod() {
alert('Hello World');
// to return some value
// return this.state.someValue;
}
render() {
return (
<h1>Hello</h1>
);
}
}
这里是源代码-
希望对你有所帮助!
你可以在这里使用另一个模式:
class Parent extends Component {
render() {
return (
<div>
<Child setClick={click => this.clickChild = click}/>
<button onClick={() => this.clickChild()}>Click</button>
</div>
);
}
}
class Child extends Component {
constructor(props) {
super(props);
this.getAlert = this.getAlert.bind(this);
}
componentDidMount() {
this.props.setClick(this.getAlert);
}
getAlert() {
alert('clicked');
}
render() {
return (
<h1 ref="hello">Hello</h1>
);
}
}
它所做的是在挂载子节点时设置父节点的clickChild方法。这样,当你点击parent中的按钮时,它会调用clickChild,它会调用child的getAlert。
如果你的子文件是用connect()包装的,那么你就不需要getWrappedInstance()了。
注意你不能使用onClick={this。在父元素中使用clickChild},因为当父元素被渲染时,子元素不会被挂载,所以这个。clickChild还没有被分配。使用onClick={() => this. clickchild()}是好的,因为当你点击按钮this. clickchild()}。clickChild应该已经被分配了。
我认为调用方法的最基本方法是在子组件上设置请求。然后,一旦子进程处理了请求,它就调用一个回调方法来重置请求。
为了能够多次发送相同的请求,重置机制是必要的。
在父组件中
在父类的渲染方法中:
const { request } = this.state;
return (<Child request={request} onRequestHandled={()->resetRequest()}/>);
父节点需要两个方法,在两个方向上与子节点进行通信。
sendRequest() {
const request = { param: "value" };
this.setState({ request });
}
resetRequest() {
const request = null;
this.setState({ request });
}
在子组件中
子进程更新其内部状态,复制来自道具的请求。
constructor(props) {
super(props);
const { request } = props;
this.state = { request };
}
static getDerivedStateFromProps(props, state) {
const { request } = props;
if (request !== state.request ) return { request };
return null;
}
最后,它处理请求,并将重置发送给父进程:
componentDidMount() {
const { request } = this.state;
// todo handle request.
const { onRequestHandled } = this.props;
if (onRequestHandled != null) onRequestHandled();
}