Calling functions from other components in react-native

Viewed 20762

How can I call functions from other components in react-native ?

I have this custom component which renders another component defined somewhere else and a image button. When tapping the image I want to call a function from the other component. 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..');
    }

    ....
}
3 Answers

Calling Remote Methods in Functional Components

To do this with functional components, you must do this:

Parent

  1. Give the child component a reference in the parent using useRef():
const childRef = useRef()
// ...
return (
   <ChildComponent ref={childRef} />
)
...

Child

  1. Pass ref into the constructor:
const ChildComponent = (props, ref) => {
  // ...
}
  1. Import useImperativeHandle and forwardRef from 'react':
import React, { useImperativeHandle, forwardRef } from 'react'
  1. Use useImperativeHandle to connect methods to the ref 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")
  }
  // ..
}
  1. Export the child component 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 './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

Related