I don't think it's even React itself that's the root cause the performance problems, it's using the data store badly (Redux or Mobx or even the new ones like Zustand and Valtio) that either causes components to rerender too often or causes too many components to rerender.
Having been bitten by this a few times, I'm paying a lot more attention to how my team uses it in the React app we're building from scratch right now, keeping an eye of how it's used and looking for problems before they become noticeable. I am, for example, inverting one of the common practices which I found was a cause of these performance problems:
"Atomic Design" with React splits components into different types - Atom, Molecule, Organism, Section/Template, Page. Each type of component is mainly composed of the smaller ones. It's generally suggested that Atoms and Molecules should be functional style and reusable, so not connected to the data store at all. Instead, Organism and up are the ones that manipulate data and pass things down into Molecules and Atoms to render. The problem here is that any update that triggers an Organism to rerender will also rerender all the Atoms and Molecules in it, even the ones that don't actually need to update (in the class-based component days we had shouldComponentUpdate() to avoid this, nowadays we have useMemo()/React.memo - neither of which we used with any consistency because of the extra effort).
Instead, while we do have a company-wide library of Atom-like elements we're using, the Atoms and Molecules inside the app are "smart" - they take a prop or two for configuration, then use that in combination with the data store to handle the data manipulation directly. Organism-level components then don't do any data wrangling and are just laying out what Molecules go where. This means when manipulating a Molecule, only that Molecule and any others looking at the same data need to rerender. The Organism and other Molecules in the same Organism are completely unaffected, not even trying to rerender and no need for React.memo to prevent it.
(Aside, to avoid confusion in the current app I haven't introduced the Atom/Molecule/Organism naming convention, and am instead using more semantic app-specific names for organizing components)
We still have a ways to go but we've already implemented the specific part I expected to cause the most problems here, and so far it's been great, the latency is so low it doesn't feel like a React app in the way I've come to expect, and there's much less manual manipulation of the data in the components themselves.