How can I call functions from other ponents in react-native ?
I have this custom ponent which renders another ponent defined somewhere else and a image button. When tapping the image I want to call a function from the other ponent. When executing the example below I get undefined is not an object (evaluating this.otherComponent.doSomething')
export default class MainComponent extends Component {
_onPressButton() {
this.otherComponent.doSomething();
}
render() {
return (
<View style={styles.container}>
<TagContainer style={styles.flow_container} ref={(instance) => this.otherComponent = instance}>
</TagContainer>
<TouchableHighlight onPress={this._onPressButton}><Image source={require('./img/ic_add.png')} style={styles.add_tags_button_view} /></TouchableHighlight>
</View>
);
}
}
and
export default class OtherComponent extends Component {
addTag() {
this.state.tags = this.state.tags.push("plm");
console.log('success..');
}
....
}
How can I call functions from other ponents in react-native ?
I have this custom ponent which renders another ponent defined somewhere else and a image button. When tapping the image I want to call a function from the other ponent. When executing the example below I get undefined is not an object (evaluating this.otherComponent.doSomething')
export default class MainComponent extends Component {
_onPressButton() {
this.otherComponent.doSomething();
}
render() {
return (
<View style={styles.container}>
<TagContainer style={styles.flow_container} ref={(instance) => this.otherComponent = instance}>
</TagContainer>
<TouchableHighlight onPress={this._onPressButton}><Image source={require('./img/ic_add.png')} style={styles.add_tags_button_view} /></TouchableHighlight>
</View>
);
}
}
and
export default class OtherComponent extends Component {
addTag() {
this.state.tags = this.state.tags.push("plm");
console.log('success..');
}
....
}
Share
Improve this question
asked May 13, 2017 at 13:37
adi.neagadi.neag
6432 gold badges12 silver badges27 bronze badges
2
- shouldn't this be: this.refs.otherComponent.addTag(); ? and <TagContainer ref="otherComponent"></TagContainer> – funkysoul Commented May 13, 2017 at 13:50
- reactnatve.wordpress./2016/05/24/refs-to-ponents – Pete Alvin Commented Nov 6, 2017 at 13:14
3 Answers
Reset to default 12Calling Remote Methods in Functional Components
To do this with functional ponents, you must do this:
Parent
- Give the child ponent a reference in the parent using
useRef()
:
const childRef = useRef()
// ...
return (
<ChildComponent ref={childRef} />
)
...
Child
- Pass
ref
into the constructor:
const ChildComponent = (props, ref) => {
// ...
}
- Import
useImperativeHandle
andforwardRef
from'react'
:
import React, { useImperativeHandle, forwardRef } from 'react'
- Use
useImperativeHandle
to connect methods to theref
object.
These 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")
}
// ..
}
- Export the child ponent using
forwardRef
:
const ChildComponent = (props, ref) => {
// ...
}
export default forwardRef(ChildComponent)
Putting it all together
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 './ponents/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-ponents
This explanation is modified from this TutorialsPoint article
Direct munication between ponents is not remended, because it breaks encapsulation. It's a good practice to send a prop to the ponent and let it handles the change inside the method ponentWillReceiveProps
.
class Main extends React.Component {
constructor(props) {
super(props);
this.state = { value: 0 };
this.handleClick = this.handleClick.bind(this);
}
handleClick(e) {
e.preventDefault();
this.setState({ value: ++this.state.value });
}
render() {
return (
<div>
<a href="#" onClick={this.handleClick}>click me</a>
<Child value={this.state.value}/>
</div>
);
}
}
class Child extends React.Component {
constructor(props) {
super(props);
this.state = { value: 0 };
}
ponentWillReceiveProps(nextProps) {
if(nextProps.value !== this.state.value) {
this.setState({ value: nextProps.value });
}
}
render() {
return <div>{this.state.value}</div>
}
}
ReactDOM.render(<Main />, document.getElementById('app'));
<script src="https://cdnjs.cloudflare./ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare./ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"/>
Need not have to define the function inside class . Here is an example
in the helpers.js
export async function getAccessKey(){
let accessToken = await AsyncStorage.getItem(ACCESS_TOKEN);
return accessToken;
}
in the calling class.
import { getAccessKey } from '../ponents/helpers';
...
//inside the method
let key = await getAccessKey();