2

I have a Component let's say:

ParenComp.js

const ParentComp = (props) => {
  const [isTrue, setIsTrue] = useState(false);
  const setToTrue = () => {
    setIsTrue(true);
  };
  const setToFalse = () => {
    setIsTrue(false);
  };
  return isTrue ? (
  
      <Text >
        This is True
      </Text>
    
  ) : (
       <Text >
        This is False
      </Text>
  );
};
export default ParentComp;

Main Question

How can I use the setToTrue and setToFalse function in other functional component in any other file for example (Login.js)?

What I tried

I want to use the inner functions in another file, I know I can not export the functions like this:

export const setToTrue = () => { setIsTrue(true); };

^ This is invalid

But what I was trying to do is (in ParentComp.js) create a reference using createRef, export it and create and export two functions that call the inside functions like this:

export const trueRef = React.createRef();
export function setToTrue() {
  let ref = trueRef.current;
  if (ref) {
    ref.setToTrue();
  }
}

export function setToFalse() {
  let ref = trueRef.current;
  if (ref) {
    ref.setToFalse();
  }
}

Now when I want to use this in my (Login.js). This is what I do:

const Login = ({ navigation }) => {
return (
<View>
<ParentComp ref={trueRef}/>
</View>
)
}

But the problem is, ref is not being passed to ParentComp here

<ParentComp ref={trueRef}/>

So, without using CLass Components, how can I pass ref to my functional component to utilize the functions inside it?

Drew Reese
  • 165,259
  • 14
  • 153
  • 181
Daniyal Shaikh
  • 419
  • 3
  • 12
  • 1
    Does this answer your question? https://stackoverflow.com/questions/68642060/trigger-child-function-from-parent-component-using-react-hooks/68642839#68642839 – Drew Reese Jan 13 '23 at 07:37
  • 1
    What you're trying to do is bad practice even if it's possible. – technophyle Jan 13 '23 at 07:44
  • @technophyle , can you elaborate why it is a bad practice? What I will achieve from this is that I will just have to use the functions to set the state, and not manage state in other files. Take the above ParentComp as a Loader. I won't have to set state on everything. I was following [this](https://stackoverflow.com/a/61840866/14267431) answer, and turning it into functional component. – Daniyal Shaikh Jan 13 '23 at 07:47
  • 1
    It's bad practice because React says it is. React components are supposed to be self-contained modules of logic and behavior. React components don't reach into other React components and pull strings, i.e. call functions, etc. The `useImperativeHandle` is essentially a backdoor for odd/obscure use cases. Similar to the Class component's [forceUpdate](https://reactjs.org/docs/react-component.html#forceupdate), it's an escape hatch. Generally if you need to force things you are doing it wrong. – Drew Reese Jan 13 '23 at 07:49
  • 1
    Because it should be your last resort to call another component's inner function. What you want to do can be simply done by passing a prop instead. – technophyle Jan 13 '23 at 07:50
  • Thankyou for your feedback Drew Reese and technophyle , but @technophyle would I be able to achieve the above by passing props, I will have to manage state in every file where I want to use them? Am I wrong? If I am, please can you give me your side of answer, I will be thankful. – Daniyal Shaikh Jan 13 '23 at 07:54
  • 1
    True but if you don't use a prop, you have to add a context objects as well. – technophyle Jan 13 '23 at 07:57
  • 1
    See [Lifting State Up](https://reactjs.org/docs/lifting-state-up.html). The idea is that the state and handlers are declared in a common ancestor component and the state/handlers passed down as props or in a Context to the component that you want to trigger updates. – Drew Reese Jan 13 '23 at 07:57
  • @DrewReese, I now understand why it is a bad practice. Thank you so much for your help – Daniyal Shaikh Jan 14 '23 at 17:39

1 Answers1

2

Use the useImperativeHandle hook with ref forwarding to give an external component access to the methods.

As noted by @technophyle and @Drew Reese in the comments, useImperativeHandle is an escape hatch that is usually used in specific cases that require direct access to a DOM node. For example, focusing an input, or scrolling to an element.

Example:

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

const ParentComp = forwardRef((props, ref) => {
  const [isTrue, setIsTrue] = useState(false);
  const setToTrue = () => { setIsTrue(true); };
  const setToFalse = () => { setIsTrue(false); };
  
  useImperativeHandle(ref, () => ({
    setToTrue,
    setToFalse
  }));
  
  return (
    <div>This is {isTrue ? 'True' : 'False'}</div>
  );
});

const Login = () => {
  const trueRef = useRef();
  
  return (
    <div>
      <ParentComp ref={trueRef}/>
      <button onClick={() => trueRef.current.setToTrue()}>True</button>
      <button onClick={() => trueRef.current.setToFalse()}>False</button>
    </div>
  );
};
  
ReactDOM
  .createRoot(root)
  .render(<Login />);
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>

<div id="root"></div>

A better way to reuse the logic, is to create a custom hook that encapsulates the behavior and use it in Login:

const { useState } = React;

const useIsTrue = () => {
  const [isTrue, setIsTrue] = useState(false);
  
  return {
    setToTrue() { setIsTrue(true); },
    setToFalse() { setIsTrue(false); },
    isTrue
  };
}

const ParentComp = ({ isTrue }) => (
  <div>This is {isTrue ? 'True' : 'False'}</div>
);

const Login = () => {
  const { setToTrue, setToFalse, isTrue } = useIsTrue();
  
  return (
    <div>
      <ParentComp isTrue={isTrue}/>
      <button onClick={setToTrue}>True</button>
      <button onClick={setToFalse}>False</button>
    </div>
  );
};
  
ReactDOM
  .createRoot(root)
  .render(<Login />);
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>

<div id="root"></div>
Ori Drori
  • 183,571
  • 29
  • 224
  • 209