Reputation: 787
I'm developing my first React Native app. What I'm trying to achieve is to execute a child function from the parent component, this is the situation:
//Child
export default class Child extends Component {
...
myfunct: function() {
console.log('Managed!');
}
...
render(){
return(
<Listview
...
/>
);
}
}
//Parent
export default class Parent extends Component {
...
execChildFunct: function() {
...
//launch child function "myfunct"
...
//do other stuff
}
render(){
return(
<View>
<Button onPress={this.execChildFunct} />
<Child {...this.props} />
</View>);
}
}
In this example, I would like to log 'Managed!'
when I press the button in the parent class. How is it feasible?
Upvotes: 52
Views: 61944
Reputation: 335
Child Component:
/* Child.js */
import React from 'react'
class Child extends React.Component {
componentDidMount() {
this.props.onRef(this) //-> important
}
componentWillUnmount() {
this.props.onRef(undefined)
}
onChange() {
alert('ok success')
}
render() {
return <View><Text>Hello World!</Text><View>
}
}
export default (Child);
Parent Component:
/* Parent.js */
import React from 'react'
import Child from './Child'
class Parent extends React.Component {
onShow = () => {
this.child.onChange()
}
render() {
return (
<View>
<Child onRef={ref => (this.child = ref)} /> **important**
<Button onPress={()=>this.onShow()} title={"button check"}/>
</View>
);
}
}
Upvotes: 0
Reputation: 1690
I think you have misunderstood something about component structure.
Assume that your child is a component which generates button for your other components. In this hierarchy your child has to inform it's parent that it was pressed.
child -----> parent
export default class Child extends Component {
return (
<Button onPress={this.props.onPress}/>
);
}
In your parent component use child component to generate a button for you. In this way, you can use child component in any other components as an independent button.
export default class Parent extends Component {
constructor(props) {
super(props);
this.execChildFunct=this.execChildFunct.bind(this);
}
execChildFunct: function() {
console.log('Managed!');
}
return (
<Child onPress={this.execChildFunct}></Child>
);
}
Upvotes: 4
Reputation: 20796
It is in reactjs.
class Child extends React.Component {
componentDidMount() {
this.props.onRef(this)
}
componentWillUnmount() {
this.props.onRef(null)
}
method() {
console.log('do stuff')
}
render() {
return <h1>Hello World!</h1>
}
}
class EnhancedChild extends React.Component {
render() {
return <Child {...this.props} />
}
}
class Parent extends React.Component {
onClick = () => {
this.child.method() // do stuff
};
render() {
return (
<div>
<EnhancedChild onRef={ref => (this.child = ref)} />
<button onClick={this.onClick}>Child.method()</button>
</div>
);
}
}
ReactDOM.render(<Parent />, document.getElementById('root'))
Original Solution:
https://jsfiddle.net/frenzzy/z9c46qtv/
https://github.com/kriasoft/react-starter-kit/issues/909
Upvotes: 8
Reputation: 7730
Simple and easy way to Parent --> Child function call
/* Parent.js */
import React, { Component } from "react";
import { TouchableOpacity, Text } from "react-native";
import Child from "./Child";
class Parent extends React.Component {
onChildClick = () => {
this.child.childFunction(); // do stuff
};
render() {
return (
<div>
<Child onRef={(ref) => (this.child = ref)} />
<TouchableOpacity onClick={this.onChildClick}>
<Text>Child</Text>
</TouchableOpacity>
</div>
);
}
}
/* Child.js */
import React, { Component } from "react";
class Child extends React.Component {
componentDidMount() {
this.props.onRef(this);
}
componentWillUnmount() {
this.props.onRef(undefined);
}
childFunction() {
// do stuff
alert("childFunction called");
}
render() {
return <View>Hello World!</View>;
}
}
Original Solution: https://github.com/kriasoft/react-starter-kit/issues/909
Upvotes: 7
Reputation: 3739
Here's how you can do this with functional components:
Parent
useRef()
to give the child component a reference in the parent:const childRef = useRef()
// ...
return (
<ChildComponent ref={childRef} />
)
...
Child
ref
as one of the constructor parameters:const ChildComponent = (props, ref) => {
// ...
}
useImperativeHandle
and forwardRef
methods from the 'react'
library:import React, { useImperativeHandle, forwardRef } from 'react'
useImperativeHandle
to bind functions to the ref
object, which will make these functions accessible to the parentThese methods won't be internally available, so you may want to use them to call internal methods.
const ChildComponent = (props, ref) => {
//...
useImperativeHandle(ref, () => ({
// each key is connected to `ref` as a method name
// they can execute code directly, or call a local method
method1: () => { localMethod1() },
method2: () => { console.log("Remote method 2 executed") }
}))
//...
// These are local methods, they are not seen by `ref`,
const localMethod1 = () => {
console.log("Method 1 executed")
}
// ..
}
forwardRef
:const ChildComponent = (props, ref) => {
// ...
}
export default forwardRef(ChildComponent)
Child Component
import React, { useImperativeHandle, forwardRef } from 'react';
import { View } from 'react-native'
const ChildComponent = (props, ref) => {
useImperativeHandle(ref, () => ({
// methods connected to `ref`
sayHi: () => { sayHi() }
}))
// internal method
const sayHi = () => {
console.log("Hello")
}
return (
<View />
);
}
export default forwardRef(ChildComponent)
Parent Component
import React, { useRef } from 'react';
import { Button, View } from 'react-native';
import ChildComponent from './components/ChildComponent';
const App = () => {
const childRef = useRef()
return (
<View>
<ChildComponent ref={childRef} />
<Button
onPress={() => {
childRef.current.sayHi()
}}
title="Execute Child Method"
/>
</View>
)
}
export default App
There is an interactive demo of this on Expo Snacks: https://snack.expo.dev/@backupbrain/calling-functions-from-other-components
This explanation is modified from this TutorialsPoint article
Upvotes: 39
Reputation: 2817
Nader Dabit's answer is outdated, since using String literals in ref attributes has been deprecated. This is how we would do it as of September 2017:
<Child ref={child => {this.child = child}} {...this.props} />
<Button onPress={this.child.myfunc} />
Same functionality, but instead of using a String to reference the component, we store it in a global variable instead.
Upvotes: 34
Reputation: 53711
You can add a ref to the child component:
<Child ref='child' {...this.props} />
Then call the method on the child like this:
<Button onPress={this.refs.child.myfunc} />
Upvotes: 26