0

I know I can pass param like the following

   someList.map((column) => {
    return (
      <th value={column} onClick={() => this.handleSort(column)}>{column}</th>
    )
   })

However it is also advised not to use arrow function or bind because that leads to unneccessary render

(edit: I think it means the component with the binded function as a prop gets re-rendered when parent component renders because functions are getting created every time when parent component renders)

But then I've not seen any other way to do it without creating a new function with bind, or arrow function .

Maybe you could create binded functions for all the items in the list, but I don't think it is feasible when you get data from props (so you can't pre-create binded functions in a constructor ?

Edit:

https://github.com/facebook/react-native/issues/7892 talks about getting component being clicked.
I guess there's no recommended public way of doing this as of now at least for react-native.

eugene
  • 39,839
  • 68
  • 255
  • 489
  • whoever told you it leads to extra render does not know how React works – João Cunha Jan 19 '18 at 14:14
  • It doesn't lead to an extra render, it just creates a new function every time it re-renders. – bamtheboozle Jan 19 '18 at 14:15
  • @Lokuzt I've added what I mean by `extra render` – eugene Jan 19 '18 at 14:20
  • @eugene I don't see the problem. I never had issues with re-rendering from function binding. And I use the simplest way possible. myFunc = () => {}; straight in the component. If you defined your components well and make use of PureComponent and shouldComponentUpdate there is no fear in using functions like that. – João Cunha Jan 19 '18 at 14:26
  • @Lokuzt I don't see how `shouldComponentUpdate` could help because functions are getting created and I don't see an easy way to decide whether two functions are equal inside `shouldComponentUpdate` – eugene Jan 19 '18 at 14:29
  • @eugene You missed the point. I'm not saying to compare functions in shouldComponentUpdate. It's to properly compare props existing in the app. I never had issues with functions being created. It has been talked about in the React community but even Chrome performance devs stated that it does not really affect performance of the app. – João Cunha Jan 19 '18 at 14:33
  • @Lokuzt Suppose you have a component-a. Because you are using it for items in a huge list, you have lots of component-a. Now suppose you are getting `this.foo.bind(this, aParam)` as one of the props to the `component-a`. You can't escape rending your 100x `component-a` every time your `component-a` 's parent renders. Am I still missing the point? – eugene Jan 19 '18 at 14:38
  • @eugene I wouldn't optimize my app by removing the binds. I would use memoization and virtualize my list using something like react-virtualized. We also shouldn't be discussing this in comments because it's no chat but I'm to understand the issue. But don't take it just from me. See https://twitter.com/ryanflorence/status/938098436045398016 He teaches React for a living. See also this post he wrote https://cdb.reacttraining.com/react-inline-functions-and-performance-bdff784f5578 – João Cunha Jan 19 '18 at 14:43
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/163498/discussion-between-lokuzt-and-eugene). – João Cunha Jan 19 '18 at 14:48

3 Answers3

0

Since your th element has a value, you could do:

<th value={column} onClick={this.handleSort}>{column}</th>

And your handleSort function could look like this:

handleSort(event) { const columnVal = event.target.value; .... }

bamtheboozle
  • 5,847
  • 2
  • 17
  • 31
  • can you use this method when there's no way to get `event.target` ? such as react-native's TouchableHighlight' ? https://facebook.github.io/react-native/docs/touchablehighlight.html – eugene Jan 19 '18 at 14:21
  • react uses synthetic event so you cannot find event.target property by default. You should use event.persist(); on the event, which will remove the synthetic event from the pool and allow references to the event to be retained by user code. – sajan Jan 19 '18 at 14:25
  • @eugene th doesn't have a value attribute. This might not work on some pesky browsers. And definetely does not work in react-native. The functions way is the only compatible way – João Cunha Jan 19 '18 at 14:25
0

I see that no one mentioned this solution found on eslint.

Pull the repeated section into its own component: This will speed up rendering, as it avoids the need to create new functions (through bind calls) on every render.

Check this sandbox for a live demo.

Edited:

There is also an answer, here on SO, that explains why it's better this way.

Daniel Andrei
  • 2,654
  • 15
  • 16
-1

You can create arrow function with such syntax:

handleSort = column => () => {
   //do something
}

render () {
   return (
      someList.map((column) => {
         return (
           <th value={column} onClick={this.handleSort(column)}>{column}</th>
         )
      })
   )
}
amaj
  • 270
  • 1
  • 2
  • 8
  • That's not how you do it – Chris Jan 19 '18 at 14:17
  • I mistook the order of arguments, what do you think about updated example ? – amaj Jan 19 '18 at 14:23
  • 1
    your onClick function will trigger on render because you are invoking it – Chris Jan 19 '18 at 14:27
  • Yes it will render and return new function, that will be invoked when onClick will be triggered. So my idea is to implement handleSort function to return new function, that can be invoked by onClick event later. – amaj Jan 19 '18 at 14:31
  • Yes, but this still returns a new function, right? :) – Chris Jan 19 '18 at 14:34