I'm sorry but I don't share your experience. I find React very easy, and short of a period of creating the baseline components and skeleton, everything else flows very fast in terms of development time. By the way, I think react in strict mode does run components twice in dev, so not running in strict mode will prevent that, and you can use a regular Promise in your useEffect.
Strict mode is not something that should be avoided. In the future versions React will do stuff that it does with strict mode today. Of course you can use a regular async function in useEffect but you'll quickly notice that it's called twice in strict mode. And you'll want to abort running fetch. Then you'll notice that responses can arrive out of order and your state updated with outdated response which happened to arrive last. It's easy to use async code in useEffect. It's not easy to use it correctly.
Whether it should or should not be avoided is a preference. That is why it's not forced. I don't want or need it. And if I do, and it's caveated with double-useEffect - so be it. I have a feeling there is a lot of overkill in your approach but of course I lack context so apologies if I'm wrong.
The fact that “strict mode” means useEffect gets called twice feels like a great example of the ways in which React is not simple.
It’s not quite directly using a promise but I was surprised I can’t use an async function in useEffect. It’s pretty common to perform async operations there, after all.
useEffect IS a great (the best?) place to put async code. I do it all the time.
The reason for strict mode rendering twice is to spot strictness related issues. Honestly I never even thought of using it so I've never experienced this.