Cross platform mobile development is tricky, and no framework or solution has fully solved the problem. I'll explain the solution I use in my day job, which has proved effective.
To give some context, I usually work on medium to large enterprise apps.
I think it's important to have access to the actual OS being developed on. If you need an iOS or Android specific feature, and a cross platform library doesn't allow it, then it's a no-goer for me.
By having access to the OS, you can craft as good a user experience as possible. You can build great UI in Xcode and Android Studio. Sometimes you need to be able to dazzle a customer, and need the full power of the native UI libraries.
This eliminates Xamarin, as you can't write some of your app in Xamarin, and the rest in native code (as far as I understand it).
Since the core is still native, how is it cross platform?
I think the most important thing to do is to move as much logic as possible into the API layer, and out of the app itself. The app should be dumb - the API tells it what to do.
For example, if the app needs to render a sidebar - let the API tell you what the contents should be. This avoids having to hard code configuration in both the Android and iOS apps. Another example is if the app needs to display certain content based on which type of user is logged in. Don't code that logic into the app - let it live in the API.
It's important to have a solid caching strategy for this to work well.
By moving as much as possible into the API layer, you can spend more time working in the language of your choice - in my case this tends to be Python, allowing backend logic to be written very quickly. It also means that changes can be deployed relatively easy - tweaking an API is trivial compared to releasing new mobile apps, which can sometimes take days to get through Apple's approval process.
One solution to cross platform development is Cordova, where the entire app is HTML and Javascript, rendered in a web view. This is fine for very simple apps. For larger apps you want a native core, as it allows you to do much more.
However, there are situations where embedding web views in your native code provides massive productivity gains. Imagine an app has to render a dashboard, containing pie charts. You can build this as a single page application in Javascript, and display it within the app as a webview. When done well, it's indistinguishable from a native implementation.
It's possible to write shared libraries for both iOS and Android in C++, and Kotlin Native. In reality though, it can end up making a project even more complex. Here's an article about how Dropbox did it if you're interested.
If developing a game, consider using Unity as games rarely need access to the native UI widgets of Android / iOS.
This is a tricky one. React Native can live side by side with native code, which is one of its great strengths. But it also makes the build process more complex than being fully native. The advantages like hot reloading are nice. Ultimately though, I prefer Swift and Kotlin to Javascript, even though it has improved enormously in recent years, and the likes of Typescript make it more suitable for developing large code bases.
I'd encourage people to check React Native out - it certainly stands out amongst other cross platform frameworks. I still think it's important to have some knowledge in the native platforms though.
In conclusion, what's worked for me is a thin native core, with a fat API, and some embedded web views where appropriate. Your mileage may vary depending on the types of apps you want to make, and the size of the team.