2

I'm using functional components.

<Column customFunc={myFunc} />

How should myFunc be defined?

function myFunc(e) { // code }

or

const myFunc = (e) => { // code }

Only when defining it using function keyword aka function declaration, I get this error from ESLint: JSX props should not use functions eslint (react/jsx-no-bind)

It looks like function expressions are not regarded as functions by ESLint and that's why it doesn't show that warning when they're used. Aside from hoisting and immutability, how should I define my functions inside a functional component? Does it have any impact on the way components render?


Also, if myFunc (which is defined inside another component) returns a JSX, is that considered bad?

function myFunc(props) { <CustomJSX {... props} controlParentState={editParentState} /> }

I get ESLint error/warning saying: Do not define components during render. React will see a new component type on every render and destroy the entire subtree’s DOM nodes and state (https://reactjs.org/docs/reconciliation.html#elements-of-different-types). Instead, move this component definition out of the parent component “App” and pass data as props. eslint (react/no-unstable-nested-components)

My problem is, if I define myFunc outside of parent component, how can I pass props to it when I call it (and would props have controlParentState in this case and would it be able to alter parent state)?

noobie
  • 411
  • 1
  • 12
  • if you have the power too, you can disable it as thats a very annoying rule. Here are the docs for it: https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md. As for passing JSX as props, I wouldn't... You can, but people normally do it for like icons and stuff. Outside of icons you should extract the JSX into it's own component and pass it some props. That said I'm not 100% what your asking on that – Shaded Feb 22 '23 at 17:08
  • 2
    I'm not asking how to disable it. I already know how. and I'm not passing JSX as props! Where did you read that in my question? – noobie Feb 22 '23 at 17:43
  • 1
    Please update the question to include a [mre]. It sounds like you're asking about [_functions_](https://en.wikipedia.org/wiki/Pure_function) vs [_closures_](https://stackoverflow.com/q/111102/438273), but there's currently no code to demonstrate an actual problem. See [ask] for more info. – jsejcksn Mar 02 '23 at 01:58
  • 1
    There's not an actual problem. I'm just asking about differences **in terms of React performance** Both work in React whether I define a function as a function declaration or assign it to a variable and use arrow function syntax. – noobie Mar 02 '23 at 02:00
  • it's just a matter of how you like to write it outside the context of `this` it makes no difference – Tachibana Shin Mar 02 '23 at 02:57
  • 1
    As the docs show, this ESLint rule is purely about functions that are recreated on every render - which can happen whichever of the two ways you choose to define the function. I can only assume, from the behaviour you describe, that you have the `allowArrowFunctions` option set in your eslint config - but you don't share that. As for the general question of which way is "better" to define functions - neither is, they're equivalent (barring edge cases, including using `this` which I assume you're not in a function component), it's just a matter of style and team agreement. – Robin Zigmond Mar 02 '23 at 19:02
  • For both question 1 and 2, the answer is: if you can define those functions outside of the component, do it, it'll cause fewer re-renders. If you can't because you need props from this component and arguments from later down the line, it's totally fine. TL;DR always declare outside if you can, otherwise don't worry. – Sheraff Mar 08 '23 at 21:01

2 Answers2

2

About JSX props should not use functions eslint (react/jsx-no-bind):

The core problem ESLint is trying to notify you is that it's inefficient to declare a function in a component, because it gets redeclared on each re-render due to strict checking.

To solve such problem, you can either move the function declaration/expression out of the component, or you might optimize if necessary using a useCallback hook to memoize the function:

function YourComponent() {
   const memoizedOnClick = useCallback(() => console.log(1), []);

   return <button onClick={memoizedOnClick}>blah</button>;
}

In that case, the function will be memoized and will hence reduce the re-renders, although I personally prefere to avoid using useCallback unless necessary. I personally stick with Dan Abramov's post about memos in general, which applies to this as well.

So, to summarize how to solve the first problem, either:

  1. Move the function outside of the component.
  2. (edge case if really necessary) use useCallback with the dependencies or none to simply memoize the function.

In both cases, you will prevent unnecessary rerenders.


About Do not define components during render. React will see a new component type on every render and destroy the entire subtree’s DOM nodes and state (https://reactjs.org/docs/reconciliation.html#elements-of-different-types). Instead, move this component definition out of the parent component “App” and pass data as props. eslint (react/no-unstable-nested-components):

There isn't that much to talk about this: you should avoid passing functions that renders components unless, once again, there is a very good reason to do to so.

To avoid such scenario, provide instead a Component (which is a function anyway) that accepts some props, and inject such props, declared outside of the rendered component (so, anywhere else literally).

Once again, this error is still related to prevent unnecessary rerenders because of strict equality checks.

briosheje
  • 7,356
  • 2
  • 32
  • 54
  • Does it matter how I define functions? – noobie Mar 07 '23 at 18:38
  • If you mean whether there is any difference between a function declaration and a function expression in such context, the answer imho is no. There is no difference. Every time the component is re-rendered the function is redeclared, hence its reference changes, hence child components will rerender because the function reference did change, regardless whether it's a function declaration or a function expression. – briosheje Mar 08 '23 at 08:53
0

Problem 1:

So, if I understand your problem correctly, you want to create a function that can accept props wherever it's defined.

This is a very simple misconception. Components can be functions in react.

Just define myFunc like this.

function MyFunc ({props}) {
// Logic goes here
return(
    <>
    {/* Your JSX */}
    </>
)

}

You don't have to pass MyFunc as a prop, just use it like a normal component. For your case, use it in the Column component like this.

<Column> <MyFunc props={props}/> </Column>

Problem 2:

Directly altering or changing the parent state from the child component defies the whole concept of React. See here

Therefore, keep MyFunc pure by making it it's own component (function) that can accept props. That's also what ESlint is saying.

Instead, move this component definition out of the parent component “App” and pass data as props.

React docs is an excellent site for further references.

K JOHN
  • 195
  • 7