0

I know it is bad practice to use inline arrow function in react component.

But what should I do when my function has arguments ?

e.g. in CustomInput I have a function to handle focus state and has an argument. I use it in onBlur and onFocus and pass parameter to it.

const CustomInput = () => {
  const [focused, setFocused] = useState(false);

  const handleFocus = (isFocus) => {
    /**
     * Some Conditions to check
     */
    setFocused(isFocus);
  };

  return (
    <input
      onFocus={() => handleFocus(true)}
      onBlur={() => handleFocus(false)}
    />
  );
};
BeHappy
  • 3,705
  • 5
  • 18
  • 59

4 Answers4

2

It really depends on the standards and conventions your company/project uses. Sometimes, inline arrow-functions are permitted, other times it is a strict rule to define a function, in which case you usually use a handleEvent template.

In the case of a strict rule against inline function declarations, you have several solutions:

  1. Avoid this problem entirely by refraining from Boolean traps.
  2. Rename handleFocus and then create handleFocus and handleBlur functions that call that function.
  3. Use a Reducer that handleFocus and handleBlur will call, each with a different action. (In my opinion, not the best solution for such a small-scale problem)
Eldar B.
  • 1,097
  • 9
  • 22
  • For solution #1 that you mentioned, how would refactor the `onFocus` and `onBlur` props? Define separate `setFocused` and `setBlurred` functions that take no arguments and just set the `focused` state to true or false within the implementation respectively? – takanuva15 Jul 25 '22 at 17:39
  • No, the second you click (or tab) inside/outside of the element it triggers – Eldar B. Jul 26 '22 at 12:24
1

The input focus will either be true or false. You can just pass in the handler function to the listeners, and because you know there will always only be two states, you can simply update the state with the inversion of the current state boolean.

If there are other arguments you think you'll need to pass in I tend to attach the data to data attributes on the element, and then destructure them from the dataset in the handler.

const { useEffect, useState } = React;

function Example() {

  const [focus, setFocus] = useState(false);

  function handleFocus(e) {
    const { text } = e.target.dataset;
    console.log(text);
    setFocus(!focus);
  }

  useEffect(() => {
    console.log(`Focused? ${focus}`);
  }, [focus]);

  return (
    <input
      data-text="This is an example"
      onFocus={handleFocus}
      onBlur={handleFocus}
    />
  );

};

// Render it
ReactDOM.render(
  <Example />,
  document.getElementById("react")
);
<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="react"></div>
Andy
  • 61,948
  • 13
  • 68
  • 95
  • 1
    That was just an example, think argument accept many values. – BeHappy Sep 19 '21 at 09:47
  • why use data attribute when you can just use as callback `(e)=>handleFocus(e,"This is an example")`? – Giorgi Moniava Sep 19 '21 at 09:51
  • I find data attributes more expressive and readable. – Andy Sep 19 '21 at 09:57
  • Fine, also his point about arrow functions confuses me, even official react docs start with arrow function in example:https://reactjs.org/docs/hooks-intro.html – Giorgi Moniava Sep 19 '21 at 10:00
  • This is a very situation-specific answer, I think OP intended to receive a bit broader solution. – Eldar B. Sep 19 '21 at 11:01
  • It answers the question that was asked @EldarB. If we all answered questions that weren't asked there would be mayhem. – Andy Sep 19 '21 at 11:07
  • What I'm trying to say is that the question itself gave this code solely as an example, and not as the only problem to focus on. – Eldar B. Sep 19 '21 at 11:15
  • But that's not how this site works. We solely look at the code at hand and help debug that, otherwise questions would be too broad, and answers unfocused. It's situation-specific because that was the situation expressed in the question. – Andy Sep 19 '21 at 11:43
  • OP literally commented on this answer saying exactly what I said, you just ignored it so I decided to remind you. You act as if that comment isn't there. – Eldar B. Sep 19 '21 at 13:53
0

I don't know if I correctly understood your question, but here is my take:

It is just about how to pass params and still get handlers to work by returning another function

const CustomInput = () => {
  const [focused, setFocused] = useState(false);

  const handleFocus = (isFocus) => () => {
    /**
     * Some Conditions to check
     */
    setFocused(isFocus);
  };

  return (
    <input
      onFocus={handleFocus(true)}
      onBlur={handleFocus(false)}
    />
  );
};

As for optimisations:

If your component re-renders, your function will be "re-created" either way. Its there you need to decide if optimisation is really needed (no premature optimisations) and if you need it that much it is accomplished by other ways:

  1. extracting function from component
  2. using useCallback (useMemo)
  3. wrapping component in React.memo()

etc...

You can play with an example here: https://codesandbox.io/s/friendly-greider-oph1f?file=/src/App.tsx

innrVoice
  • 75
  • 1
  • 7
-2

use the function after binding this to null like:

<input
      onFocus={handleFocus.bind(null,true)}
      onBlur={handleFocus.bind(null,false)}
/>
Alan Omar
  • 4,023
  • 1
  • 9
  • 20