0

There are a few questions with similar wording but none that helps me.

I have a parent component, that wants to pass a function to a child component through Props, and the child component will execute the function within its logic. However, ESLint is returning me the error "JSX props should not use functions react/jsx-no-bind". I understand that this is inefficient because the function will be re-created everytime the component re-renders. What would be the correct way to do this?

Parent Component

function App() {
  const [recipes, setRecipes] = useState(sampleRecipes);

  function handleRecipeAdd() {
    const newRecipe = // some logic to create newRecipe here
    setRecipes([...recipes, newRecipe]);
    
  }

  return <RecipeList recipes={recipes} handleRecipeAdd={handleRecipeAdd} />;
}

Child Component

interface Props {
  handleRecipeAdd: () => void;
}

export default function RecipeList(props: Props) {
  const { handleRecipeAdd } = props;
  return (
        <button onClick={handleRecipeAdd}>
          Add Recipe
        </button>
  );
}

Note that this is not the exact code for both components, it has been simplified to remove irrelevant code.

Samson
  • 1,336
  • 2
  • 13
  • 28
  • 2
    see [this](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md#react-hooks) in the ESLint docs. As it says, this is what `useCallback` is for – Robin Zigmond Dec 23 '21 at 18:55
  • [Why shouldn't JSX props use arrow functions or bind?](https://stackoverflow.com/questions/36677733/why-shouldnt-jsx-props-use-arrow-functions-or-bind) is a good discussion of why you wouldnt want to use arrow functions as props. That being said, I disagree completely. You can use `React.useCallback` to avoid the function being recreated on every rerender. – Seth Lutske Dec 23 '21 at 18:56
  • 1
    Thanks both! You are both absolutely right, I learnt something new today. Robin if you could post this in the form of an answer instead of comment, I would gladly upvote and accept it as the answer. – Samson Dec 23 '21 at 19:13
  • Inline functions are fine, this eslint rule is outdated. – krirkrirk Dec 23 '21 at 19:44
  • @krirkrirk even without useCallback? – Samson Dec 24 '21 at 07:39
  • @Samson yes. [Great read](https://medium.com/@ryanflorence/react-inline-functions-and-performance-bdff784f5578) – krirkrirk Dec 24 '21 at 12:38
  • Thanks @krirkrirk! I have read this article before, but it was talking about inline functions specifically, while in my case it's abit different. According to the article though, should I discard eslint entirely? – Samson Dec 25 '21 at 07:34
  • @Samson [Even better read for your case](https://kentcdodds.com/blog/usememo-and-usecallback) . To put it shortly, premature optimization is the root of all evil, and yes I would discard this eslint rule entirely. Which by the way doesn't mean that useCallback is useless, but you should use it when it is truly necessary, not by principle. – krirkrirk Dec 25 '21 at 18:17

2 Answers2

1

Huge thanks to Robin Zigmond for pointing me to the correct place to look at, this has been resolved with the useCallback hook. For anyone who is interested, here's what the updated code looks like:

Parent Component

function App() {
  const [recipes, setRecipes] = useState(sampleRecipes);

  const handleRecipeAdd = useCallback(() => {
    const newRecipe = // some logic to create newRecipe here
    setRecipes([...recipes, newRecipe]);
  }, [recipes]);

  return <RecipeList recipes={recipes} handleRecipeAdd={handleRecipeAdd} />;
}
Samson
  • 1,336
  • 2
  • 13
  • 28
0
function App() {
  const [recipes, setRecipes] = useState(sampleRecipes);

  const handleRecipeAdd = useCallback(() => {
    const newRecipe = // some logic to create newRecipe here
    setRecipes(recipes => {
        return [...recipes, newRecipe];
    });
  }, [setRecipes]);

  return <RecipeList recipes={recipes} handleRecipeAdd={handleRecipeAdd} />;
}
theZ3r0CooL
  • 147
  • 2
  • 10