In theory, there are four fundamental approaches.
1. Separate stacks, native widgets
2. Shared stack, native widgets
3. Separate stacks, custom widgets
4. Shared stack, custom widgets
React Native uses methods 1 and 2. They have unified components that can be used across platforms, but they lack features, so most complex apps use the second approach. The big wins are a more known language (JS) and sharing a bunch of the "backend of the frontend".
The big downside happens when you add more systems (eg, web, OSX, Windows, Linux, etc). When you do this, the intersection shrinks and the potential for bugs in the shared widget increase dramatically.
Flutter uses methods 3 and 4. Rather than using the native widgets, they carry along Skia to do the rendering for them. This neatly skips most of the UI intersection issues because if the native widget for X lacks a certain feature, you can add it yourself in your custom widget. When dramatically different looks are desired, you can still use separate widgets for different systems. Adding additional systems is usually less difficult because rather than writing hooks into everything on the system, you only need more basic system hooks and the effort to get the renderer working.
The big downside here is development time and little inconsistencies. Instead of leveraging the work already done by the native developers (who probably know their system much better than the library's devs), everything must be built from scratch. Getting 90% there is easy, but getting every little detail working so it feels native is much harder. In addition, you must keep up with native widget changes which generally adds a lag time between their release and your catchup (but on the plus side, you may have already implemented some features they were missing). It should also be added that some UI features may not be available on some platforms (despite the shared widget) simply because the underlying OS does not support them, so multiple components may still be necessary for some things.
Both approaches have been tried in the past. Qt is probably the most successful at cross-platform design and they use the 3rd and 4th methods. I'm inclined to think its a better solution in the end even if it is more costly.