2

Please follow my code snippet below, When I click on any button (add, edit, remove) all my components gets re-render including the Title component which has no props or stats. It may be fine if I have a few components but lets assume that I have over 15 or more with fetching / saving data, is that OK or should be avoided?

I've tried to use useCallback hooks (with handleRemove) but obviously that doesn't work as intended.

const Button = ({ title, count, onClick }) => {
  console.log(`Rendering ${title}`)
  return (
    <button onClick={onClick}>
      {title} ({count})
    </button>
  )
}
const Header = () => {
  console.log("Rendering Title")
  return <h1>App Title</h1>
}

const Parent = () => {
  const [add, setAdd] = React.useState(0)
  const [edit, setEdit] = React.useState(0)
  const [remove, setRemove] = React.useState(0)
  
  const handleAdd = () => setAdd(add + 1)
  const handleEdit = () => setEdit(edit + 1)
  const handleRemove = React.useCallback(() => {
    setRemove(remove + 1)
  }, [remove])

  return (
    <React.Fragment>
      <Header />
      <Button title="Add" onClick={handleAdd} count={add} />
      <Button title="Edit" onClick={handleEdit} count={edit} />
      <Button title="Remove" onClick={handleRemove} count={remove} />
    </React.Fragment>
  )
}

function App() {
  return (
    <div className="App">
      <Parent />
      <button onClick={console.clear}>Clear log</button>
    </div>
  )
}

ReactDOM.render( <App /> , document.getElementById('root'))
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>
CasandraH
  • 43
  • 1
  • 6

2 Answers2

6

There's some more advanced info in the comments and in another answer, but I wanted to address something more basic about how React works, and about:

It may be fine if I have a like few components but lets assume that I have over 15 or more with fetching/saving data, is that OK or should be avoided?

In React, even if a component is "re-rendered" ... in the sense that its function is called repeatedly ... it does not "re-render" in the most important (ie. expensive) place: in the actual DOM. Or rather, it doesn't unless the function returns something different.

Thus, every time you see a console.log in a React component, it only means the virtual DOM was involved, and so the cost of that change is much, much lower (again, assuming your component keeps returning identical JSX).

Now of course any function call still has a cost, and you want to ultimately minimize the number of times your components render, but at the same time it's important to remember the words of the famous programmer Donald Knuth:

premature optimization is the root of all evil

If you're not even seeing even the slightest hint of a performance issue, then worrying about exactly how many times a component renders in the virtual DOM kind of makes you miss out on some of the genius of React: you trade tons of the most expensive resource (your thinking) for "performance optimizations" no human can even observe.

Instead, you absolutely want to read more about the library, to understand what triggers render calls (essentially props/state/context changes, but there are important details), and try to understand and improve performance in that way. Learning all that is part of "leveling up" in React.

But, especially if you're just learning the library, you really don't need to worry about re-rendering any particular component a few extra times, because React was designed very cleverly to let us focus on what our components do, and not exactly how it's done ... or at least most of the time (I certainly don't want to make it sound like React is a "magic performance bullet" either).

machineghost
  • 33,529
  • 30
  • 159
  • 234
  • 1
    You are absolutely right, I care too much about performance and I shouldn't but the thing is I'm still learning and (while I'm), I like to follow or at least know the best practices. I like to know how things works not just make another "ToDo" App :) Thank you, I really appreciate your time and your valuable advice. – CasandraH Apr 10 '20 at 01:54
1

If any state changes in a component, it will get rerendered. Consider moving the state down into the button component itself, if the state is not meant to be shared across components. This will only cause the <AddButton/> component to get re-rendered when onClick is fired.

const AddButton = () => {
 const [add, setAdd] = React.useState(0)
 const handleAdd = () => setAdd(add + 1)

  return ( <Button title="Add" onClick={handleAdd} count={add} />)
 }
Doug
  • 14,387
  • 17
  • 74
  • 104