Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Executing function in child component from parent

I'm using React Native, and I have a functional component that has a function in it. This child component is located inside another component, on that another component I have a button. So, When the user clicks the button, I want to execute the function in the child component.

I read about forwardRef (as I saw few questions about this that suggested this solution): https://reactjs.org/docs/forwarding-refs.html But it does not seems to fit my problem. I don't need to access an element in my child component, only to execute the function.

This is my child component:

  const Popup = () => {
  const opacity = useRef(new Animated.Value(1)).current;
  const translationY = useRef(new Animated.Value(-120)).current;

  const {theme} = useContext(ThemeContext);

  const displayPopup = () => {
    Animated.spring(translationY, {
      toValue: 100,
      useNativeDriver: true,
    }).start();
  };

  return (
    <Animated.View
      style={[
        styles.container,
        {
          backgroundColor: theme.popup,
          opacity: opacity,
          transform: [{translateY: translationY}],
        },
      ]}>
     ...
    </Animated.View>
  );
};

Inside the parent component:

<SafeAreaView>
      // Other components
      <Popup />
      <Button onPress={() => {//NEEDS TO CALL displayPopup}}/>
</SafeAreaView>
like image 667
John Doah Avatar asked Apr 13 '26 11:04

John Doah


2 Answers

Using a forward ref to give access to a child function can be a solution, but it's not the React way to do it (See useImperativeHandle hook)

Instead, I would change a props of the Popup component to trigger the animation you want to use:

import { useEffect } from "react";

 const Popup = ({display = false}) => {
  const opacity = useRef(new Animated.Value(1)).current;
  const translationY = useRef(new Animated.Value(-120)).current;

  const {theme} = useContext(ThemeContext);

  useEffect(() => {
      if(display){
        Animated.spring(translationY, {
            toValue: 100,
            useNativeDriver: true,
        }).start();
      } 
  }, [display])

  return (
    <Animated.View
      style={[
        styles.container,
        {
          backgroundColor: theme.popup,
          opacity: opacity,
          transform: [{translateY: translationY}],
        },
      ]}>
     ...
    </Animated.View>
  );
};

Parent component:


const [display, setDisplay] = useState(false);

return(
   <SafeAreaView>
      // Other components
      <Popup display={display} />
      <Button onPress={() => {setDisplay(true)}}/>
    </SafeAreaView> 
)
like image 51
Onlinogame Avatar answered Apr 15 '26 02:04

Onlinogame


You can use a ref forward it to the child component and use useImparativeHandle in the child to augment the ref so that the parent can invoke it.

Just run this code snippet:

const { useState, useRef, createRef, forwardRef, useImperativeHandle } = React;

const TextInput = forwardRef(({value, otherProps}, ref) => {
  const [text, setText] = useState(value || "");

  const clearText = () => setText("");

  // augment the ref by adding the clearText function
  useImperativeHandle(ref, () => ({
    clearText
  }));

  return (
    <input ref={ref} type="text" onChange={(e) => setText(e.target.value)}
       value={text} {...otherProps}
    />
  );
});

const Parent = () => {
  const textRef = createRef();
  const onClickButton = () => textRef.current.clearText();

  return (
    <div>
      <TextInput ref={textRef} value="Enter Text" />
      <button onClick={() => onClickButton()}>Clear Text</button>
    </div>
  );
};

ReactDOM.render(<Parent />, document.getElementById("root"));
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>

As the React docs states

As always, imperative code using refs should be avoided in most cases.

and later they say

In this example, a parent component that renders would be able to call inputRef.current.focus().

It's up to you to decide if your code is one of the few cases in which it makes sense.

like image 39
René Link Avatar answered Apr 15 '26 02:04

René Link



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!