user10336550
user10336550

Reputation:

Is it possible to pass a React.hook to a function?

Can I pass React.hooks to a function and use it there?

    const [X, setX] = useState('');

    function  Y(useX){
       useX('string');
    }
    Y(setX)

Upvotes: 7

Views: 16480

Answers (3)

jayarjo
jayarjo

Reputation: 16716

When using hooks, you must abide to certain hook rules (there are only two at the moment):

  1. Only Call Hooks at the Top Level
  2. Only Call Hooks from React Functions

By attempting to pass a hook to a regular function you are violating both of them. And while these rules are more of conventions, than actual restrictions and might work (as others in this thread have mentioned) in some cases (either you knowing where and why you can use them or you accidentally fulfilling their usage requirements) it is not recommended to use them in such way. For example, after some time you might forget that your function contains a hook and actually depends on where and how it is declared and used, and move it around, or put into a conditional, effectively breaking the logic of your application.

It is so important that React folks came up with the dedicated ESlint plugin that is meant to analyze your code in the background and warn you exactly when you are close to violating hook rules. It's the way to know for sure.

If you still need to extract some hook dependent logic from your component to a separate function, consider creating a custom hook.

BUT!

In your sample code you are not passing a hook to a function. React.useState is a hook, but the setX that it returns is not. You can pass it around however you like, and you actually are meant to pass it to your custom made regular functions or custom hooks!

Upvotes: 17

Shubham Khatri
Shubham Khatri

Reputation: 281646

As the rule states, hooks can only be called at the top of the functional component and shouldn't be called conditionally, so while technically you can pass it as an argument of a function, but then you would need to execute the function immediately

So

const App = () => {
    const [X, setX] = React.useState('x');

    function Y(useX){
       useX('string');
    }

    Y(React.useState);
    
    return <div>Hello {X}</div>
}

ReactDOM.render(<App/>, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="app" />

would be okay.

But below code won't work

const App = () => {
    const [X, setX] = React.useState('x');

    function Y(useX){
       useX('string');
    }
    
    
    return <div>Hello {X} <button onClick={() => {Y(React.useState)}}>Click</button></div>
}

ReactDOM.render(<App/>, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="app" />

Hence you should not use it this way because it may so happen that you later add some statements within function calls and hence the hook is not preserving the order of its call

Maintaining the order of Hooks invocation is required because React relies on hooks call order to maintain a queue of hooks being used in the method and process all further updates

Technically if useX is a custom hook, it essentially a function that is invoked from within a component that contains hooks at the top level

Upvotes: 0

Estus Flask
Estus Flask

Reputation: 222344

In this case it's not a hook but setter function that is passed, hook limitations aren't applicable to to Y(setX). It shouldn't necessarily reside in component scope:

function  Y(setX){
  setX('string');
}

const Comp = () => {
  const [X, setX] = useState('');
  Y(setX);
  ...
}

Depending on the usage it can benefit from memoization, for instance if () => Y(setX) should be passed as a prop:

const Comp = () => {
  const [X, setX] = useState('');
  const setY = useCallback(() => Y(setX), []);
  ...
}

Upvotes: -1

Related Questions