Evo*_* SL 358 javascript reactjs
我有两个组成部分.
我试图从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>
);
}
}
Run Code Online (Sandbox Code Playgroud)
有没有办法从父母那里调用孩子的方法?
注意:Child和Parent组件位于两个不同的文件中
ros*_*dia 518
首先,请允许我表示,这通常不是 React土地上的事情.通常,您要做的是将功能传递给道具中的子项,并在事件中传递来自子项的通知.
但是,如果必须在子组件上公开命令式方法,则可以使用refs.请记住,这是一个逃生舱,通常表明有更好的设计可用.
以前,refs仅支持基于类的组件.随着React Hooks的出现,情况已不再如此
dispatch)const { forwardRef, useRef, useImperativeHandle } = React;
// We need to wrap component in `forwardRef` in order to gain
// access to the ref object that is assigned using the `ref` prop.
// This ref is passed as the second parameter to the function component.
const Child = forwardRef((props, ref) => {
// The component instance will be extended
// with whatever you return from the callback passed
// as the second argument
useImperativeHandle(ref, () => ({
getAlert() {
alert("getAlert from Child");
}
}));
return <h1>Hi</h1>;
});
const Parent = () => {
// In order to gain access to the child component instance,
// you need to assign it to a `ref`, so we call `useRef()` to get one
const childRef = useRef();
return (
<div>
<Child ref={childRef} />
<button onClick={() => childRef.current.getAlert()}>Click</button>
</div>
);
};
ReactDOM.render(
<Parent />,
document.getElementById('root')
);Run Code Online (Sandbox Code Playgroud)
文档>= react@16.8是在这里:
useImperativeHandle()自定义使用时向父组件公开的实例值useImperativeHandle.
<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
<div id="root"></div>Run Code Online (Sandbox Code Playgroud)
ref)出于历史目的,这里是您在16.3之前使用React版本的基于回调的样式:
const { Component } = React;
class Parent extends Component {
constructor(props) {
super(props);
this.child = React.createRef();
}
onClick = () => {
this.child.current.getAlert();
};
render() {
return (
<div>
<Child ref={this.child} />
<button onClick={this.onClick}>Click</button>
</div>
);
}
}
class Child extends Component {
getAlert() {
alert('getAlert from Child');
}
render() {
return <h1>Hello</h1>;
}
}
ReactDOM.render(<Parent />, document.getElementById('root'));Run Code Online (Sandbox Code Playgroud)
<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
<div id="root"></div>Run Code Online (Sandbox Code Playgroud)
小智 110
您可以在此处使用其他模式:
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>
);
}
}
Run Code Online (Sandbox Code Playgroud)
它的作用是在挂载子进程时设置父进程的clickChild方法.这样,当您单击父级中的按钮时,它将调用clickChild,该单元调用child的getAlert.
如果您的孩子用connect()包装,这也适用,因此您不需要getWrappedInstance()hack.
请注意,您不能在父级中使用onClick = {this.clickChild},因为在呈现父级时未挂载子级,因此尚未分配this.clickChild.使用onClick = {()=> this.clickChild()}很好,因为当您单击按钮时,应该已经分配了this.clickChild.
Kas*_*sra 99
在这里我将向您提供四种可能发生的组合:
class Parent extends React.Component {
constructor(props) {
super(props)
this.myRef = React.createRef()
}
render() {
return (<View>
<Child ref={this.myRef}/>
<Button title={'call me'}
onPress={() => this.myRef.current.childMethod()}/>
</View>)
}
}
const Child = React.forwardRef((props, ref) => {
useImperativeHandle(ref, () => ({
childMethod() {
childMethod()
}
}))
function childMethod() {
console.log('call me')
}
return (<View><Text> I am a child</Text></View>)
})
Run Code Online (Sandbox Code Playgroud)
function Parent(props) {
const myRef = useRef()
return (<View>
<Child ref={myRef}/>
<Button title={'call me'}
onPress={() => myRef.current.childMethod()}/>
</View>)
}
class Child extends React.Component {
childMethod() {
console.log('call me')
}
render() {
return (<View><Text> I am a child</Text></View>)
}
}
Run Code Online (Sandbox Code Playgroud)
function Parent(props) {
const myRef = useRef()
return (<View>
<Child ref={myRef}/>
<Button title={'call me'}
onPress={() => myRef.current.childMethod()}/>
</View>)
}
const Child = React.forwardRef((props, ref) => {
useImperativeHandle(ref, () => ({
childMethod() {
childMethod()
}
}))
function childMethod() {
console.log('call me')
}
return (<View><Text> I am a child</Text></View>)
})
Run Code Online (Sandbox Code Playgroud)
class Parent extends React.Component {
constructor(props) {
super(props)
this.myRef = React.createRef()
}
render() {
return (<View>
<Child ref={this.myRef}/>
<Button title={'call me'}
onPress={() => this.myRef.current.childMethod()}/>
</View>)
}
}
class Child extends React.Component {
childMethod() {
console.log('call me')
}
render() {
return (<View><Text> I am a child</Text></View>)
}
}
Run Code Online (Sandbox Code Playgroud)
ton*_*ral 72
使用 useEffect 的替代方法:
家长:
const [refresh, doRefresh] = useState(0);
<Button onClick={() => doRefresh(prev => prev + 1)} />
<Children refresh={refresh} />
Run Code Online (Sandbox Code Playgroud)
孩子们:
useEffect(() => {
performRefresh(); //children function of interest
}, [props.refresh]);
Run Code Online (Sandbox Code Playgroud)
小智 28
https://facebook.github.io/react/tips/expose-component-functions.html 获取更多答案ref here 在React子组件上调用方法
通过查看"原因"组件的引用,您将破坏封装并使得无法在不仔细检查其使用的所有位置的情况下重构该组件.因此,我们强烈建议将refs视为组件的私有,就像状态一样.
通常,数据应该通过props传递到树下.这有一些例外(例如调用.focus()或触发一次性动画并不真正"改变"状态)但是当你暴露一个名为"set"的方法时,通常会出现道具一个更好的选择.尝试做到这一点,以便内部输入组件担心它的大小和外观,以便它的祖先没有.
Bla*_*mba 18
我正在使用useEffecthook 来克服执行这一切的麻烦,所以现在我将一个变量传递给 child,如下所示:
import { useEffect, useState } from "react";
export const ParentComponent = () => {
const [trigger, setTrigger] = useState(false);
return (
<div onClick={() => { setTrigger(trigger => !trigger); }}>
<ChildComponent trigger={trigger}></ChildComponent>
</div>
);
};
export const ChildComponent = (props) => {
const triggerInvokedFromParent = () => {
console.log('TriggerInvokedFromParent');
};
useEffect(() => {
triggerInvokedFromParent();
}, [props.trigger]);
return <span>ChildComponent</span>;
};Run Code Online (Sandbox Code Playgroud)
Pet*_*rth 13
我希望我没有重复上面的任何内容,但是传递一个在父级中设置函数的回调道具呢?这很有效,而且很容易。(添加的代码位于 //// 之间)
class Parent extends Component {
/////
getAlert = () => {} // initial value for getAlert
setGetAlertMethod = (newMethod) => {
this.getAlert = newMethod;
}
/////
render() {
return (
<Child setGetAlertMethod={this.setGetAlertMethod}>
<button onClick={this.getAlert}>Click</button>
</Child>
);
}
}
class Child extends Component {
/////
componentDidMount() {
this.props.setGetAlertMethod(this.getAlert);
}
/////
getAlert() => {
alert('clicked');
}
render() {
return (
<h1 ref="hello">Hello</h1>
);
}
}
Run Code Online (Sandbox Code Playgroud)
And*_*Dev 12
我对这里提供的任何解决方案都不满意。实际上有一个非常简单的解决方案,可以使用纯 Javascript 来完成,而不依赖于基本 props 对象以外的一些 React 功能 - 它为您提供了双向通信的好处(父 -> 子,子 -> 父)。您需要将一个对象从父组件传递给子组件。这个对象就是我所说的“双向引用”或简称 biRef。基本上,该对象包含对父级想要公开的父级方法的引用。并且子组件将方法附加到父组件可以调用的对象上。像这样的东西:
// Parent component.
function MyParentComponent(props) {
function someParentFunction() {
// The child component can call this function.
}
function onButtonClick() {
// Call the function inside the child component.
biRef.someChildFunction();
}
// Add all the functions here that the child can call.
var biRef = {
someParentFunction: someParentFunction
}
return <div>
<MyChildComponent biRef={biRef} />
<Button onClick={onButtonClick} />
</div>;
}
// Child component
function MyChildComponent(props) {
function someChildFunction() {
// The parent component can call this function.
}
function onButtonClick() {
// Call the parent function.
props.biRef.someParentFunction();
}
// Add all the child functions to props.biRef that you want the parent
// to be able to call.
props.biRef.someChildFunction = someChildFunction;
return <div>
<Button onClick={onButtonClick} />
</div>;
}
Run Code Online (Sandbox Code Playgroud)
此解决方案的另一个优点是您可以在父和子中添加更多函数,同时仅使用单个属性将它们从父传递给子。
对上述代码的改进是不将父函数和子函数直接添加到 biRef 对象,而是添加到子成员。父函数应该添加到名为“parent”的成员中,而子函数应该添加到名为“child”的成员中。
// Parent component.
function MyParentComponent(props) {
function someParentFunction() {
// The child component can call this function.
}
function onButtonClick() {
// Call the function inside the child component.
biRef.child.someChildFunction();
}
// Add all the functions here that the child can call.
var biRef = {
parent: {
someParentFunction: someParentFunction
}
}
return <div>
<MyChildComponent biRef={biRef} />
<Button onClick={onButtonClick} />
</div>;
}
// Child component
function MyChildComponent(props) {
function someChildFunction() {
// The parent component can call this function.
}
function onButtonClick() {
// Call the parent function.
props.biRef.parent.someParentFunction();
}
// Add all the child functions to props.biRef that you want the parent
// to be able to call.
props.biRef {
child: {
someChildFunction: someChildFunction
}
}
return <div>
<Button onClick={onButtonClick} />
</div>;
}
Run Code Online (Sandbox Code Playgroud)
通过将父函数和子函数放入 biRef 对象的单独成员中,您将清楚地分离两者并轻松查看哪些属于父函数或子函数。如果相同的函数出现在两个子组件中,它还有助于防止子组件意外覆盖父函数。
最后一件事是,如果您注意到,父组件使用 var 创建 biRef 对象,而子组件通过 props 对象访问它。在父级中不定义 biRef 对象并通过其自己的 props 参数从其父级访问它可能很诱人(在 UI 元素的层次结构中可能就是这种情况)。这是有风险的,因为孩子可能认为它正在调用父级的函数属于父级,而实际上它可能属于祖父级。只要你意识到这一点,这并没有错。除非您有理由支持父/子关系之外的某些层次结构,否则最好在父组件中创建 biRef。
Roh*_*rte 12
对于功能组件最简单的方法是
父组件
父级.tsx
import React, { useEffect, useState, useRef } from "react";
import child from "../../child"
const parent: React.FunctionComponent = () => {
const childRef: any = useRef();
const onDropDownChange: any = (event): void => {
const target = event.target;
childRef.current.onFilterChange(target.value);
};
return <child ref={childRef} />
}
export default parent;
Run Code Online (Sandbox Code Playgroud)
子组件
孩子.tsx
import React, { useState, useEffect, forwardRef, useRef, useImperativeHandle, } from "react";
const Child = forwardRef((props, ref) => {
useImperativeHandle(ref, () => ({
onFilterChange(id) {
console.log("Value from parent", id)
},
}));
})
Child.displayName = "Child";
export default Child;
Run Code Online (Sandbox Code Playgroud)
您可以使用ref从父级调用子组件的功能
在功能组件中,您必须使用useImperativeHandleref 进入像下面这样的孩子
import React, { forwardRef, useRef, useImperativeHandle } from 'react';
export default function ParentFunction() {
const childRef = useRef();
return (
<div className="container">
<div>
Parent Component
</div>
<button
onClick={() => { childRef.current.showAlert() }}
>
Call Function
</button>
<Child ref={childRef}/>
</div>
)
}
const Child = forwardRef((props, ref) => {
useImperativeHandle(
ref,
() => ({
showAlert() {
alert("Child Function Called")
}
}),
)
return (
<div>Child Component</div>
)
})
Run Code Online (Sandbox Code Playgroud)
儿童.js
import s from './Child.css';
class Child extends Component {
getAlert() {
alert('clicked');
}
render() {
return (
<h1>Hello</h1>
);
}
}
export default Child;
Run Code Online (Sandbox Code Playgroud)
父.js
class Parent extends Component {
render() {
onClick() {
this.refs.child.getAlert();
}
return (
<div>
<Child ref="child" />
<button onClick={this.onClick}>Click</button>
</div>
);
}
}
Run Code Online (Sandbox Code Playgroud)
如果您这样做仅仅是因为您希望 Child 为其父母提供可重用的特征,那么您可以考虑使用 render-props来做到这一点。
该技术实际上将结构颠倒了。在Child现在包装了父母,所以我改名到AlertTrait下面。我保留了Parent连续性的名字,虽然它现在不是真正的父母。
// Use it like this:
<AlertTrait renderComponent={Parent}/>
class AlertTrait extends Component {
// You will need to bind this function, if it uses 'this'
doAlert() {
alert('clicked');
}
render() {
return this.props.renderComponent({ doAlert: this.doAlert });
}
}
class Parent extends Component {
render() {
return (
<button onClick={this.props.doAlert}>Click</button>
);
}
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下, AlertTrait 提供一个或多个特征,它作为道具传递给它在其renderComponent道具中给出的任何组件。
ParentdoAlert作为 prop接收,可以在需要时调用它。
(为了清楚起见,我renderComponent在上面的示例中调用了 prop 。但是在上面链接的 React 文档中,他们只是调用了它render。)
Trait 组件可以在其渲染函数中渲染 Parent 周围的东西,但它不会在父级内部渲染任何东西。实际上它可以在 Parent 内部渲染东西,如果它传递另一个 prop(例如renderChild)给父级,然后父级可以在其渲染方法中使用。
这与 OP 要求的有些不同,但有些人可能会在这里(就像我们一样)因为他们想要创建一个可重用的特征,并认为子组件是一个很好的方法来做到这一点。
我们可以通过其他方式使用refs-
我们将创建一个Parent元素,它将渲染一个<Child/>组件。如您所见,将要渲染的组件需要添加ref属性并为其提供名称。
然后,triggerChildAlert位于父类中的函数将访问此上下文的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>
);
}
}
Run Code Online (Sandbox Code Playgroud)
现在,按照先前的理论设计,子组件将如下所示:
class Child extends React.Component {
callChildMethod() {
alert('Hello World');
// to return some value
// return this.state.someValue;
}
render() {
return (
<h1>Hello</h1>
);
}
}
Run Code Online (Sandbox Code Playgroud)
这是源代码-
希望能为您服务!
此模式类似于@brickingup答案。但在此版本中,您可以设置任意数量的子操作。
import { useEffect } from "react";
export const Parent = () => {
const childEvents = { click: () => {} };
return (
<div onClick={() => childEvents.click()}>
<Child events={childEvents}></Child>
</div>
);
};
export const Child = (props) => {
const click = () => {
alert("click from child");
};
useEffect(() => {
if (props.events) {
props.events.click = click;
}
}, []);
return <span>Child Component</span>;
};
Run Code Online (Sandbox Code Playgroud)
逻辑很简单。
Create a function in parent using child or use ref.
我更喜欢父级使用子级的创建功能。有多种方法可以做到这一点。
使用功能组件时
function Parent(){
const [functionToCall, createFunctionToCall] = useState(()=>()=>{})
return (
<Child createFunctionToCall={createFunctionToCall} />
)
}
Run Code Online (Sandbox Code Playgroud)
function Child({createFunctionToCall}){
useEffect(()=>{
function theFunctionToCall(){
// do something like setting something
// don't forget to set dependancies properly.
}
createFunctionToCall(()=>theFunctionToCall)
},[createFunctionToCall])
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
235413 次 |
| 最近记录: |