React Native is an excellent entering point to app development for a web developer, especially with React experiences.
In the current architecture, the communication between these threads happens over the library called "bridge".
The React Native team is actively working on the major architecture upgrade and this article gives a great overview of why and how the change is needed.
I don't get into the details, but the basic understanding of the current and future architecture helps to model your application, especially to separate the concerns.
As you can see above, React Native covers a significantly broader area than React itself.
React for the web looks rather intuitive as the key concept, the Virtual DOM, implies the browsers' HTML dom rendering. But in-fact, the Virtual DOM is not tied to the HTML DOM (Document Object Model). The Virtual DOM in React is more of a programming concept or a pattern than a specific technology.
It provides an abstraction for the declarative UI. The virtual representation of a UI is kept in memory and synced with the external UI libraries. This process is called reconciliation.
You can read a good explanation of the React Fiber Architecture here.
Reconciliation versus rendering
The DOM is just one of the rendering environments React can render to, the other major targets being native iOS and Android views via React Native. (This is why "virtual DOM" is a bit of a misnomer.)
The reason it can support so many targets is because React is designed so that reconciliation and rendering are separate phases. The reconciler does the work of computing which parts of a tree have changed; the renderer then uses that information to actually update the rendered app.
This separation means that React DOM and React Native can use their own renderers while sharing the same reconciler, provided by React core.
Fiber reimplements the reconciler. It is not principally concerned with rendering, though renderers will need to change to support (and take advantage of) the new architecture.
The native components cover comprehensive native UI elements, but you still need to write a lot of code to simulate the native user experience such as tab navigation. That's where React Navigation comes in.
It provides the best practice of how to structure and navigate the app screens, which is one of the most confusing parts when you come from a web development background.
My advice is to stick to the basic navigation patterns until you are confident, and you can implement your custom navigators on top of React Navigation once you have the good overviews. I would also prefer to place navigators and screens into the dedicated directories to clearly separate them from the other components.
Despite the difference in the UI implementations, the thought process of building a new application stays the same as "Thinking in React" way.
- Start With A Mock
- Break The UI Into A Component Hierarchy
- Build A Static Version in React
- Identify The Minimal (but complete) Representation Of UI State
- Identify Where Your State Should Live
- Add Inverse Data Flow
React 16.8.0 introduced Hooks in 2019, and it was a big paradigm shift. The React team expects Hooks to replace all the Class Component use cases, and the popular libraries have already migrated toward this direction, for example, React Navigation 5.0 and React Redux 7.1.0 introduced their Hook APIs.
Conceptually, React components have always been closer to functions, and "Thinking in React" way became more straight forward with Hooks.
The motivation behind Hooks explains the benefits:
Hooks let you split one component into smaller functions based on what pieces are related (such as setting up a subscription or fetching data), rather than forcing a split based on lifecycle methods. You may also opt into managing the component's local state with a reducer to make it more predictable.
- assigned to variables
- used as functional parameters
- returned from a function
Like this example in Hooks FAQ, it is very important to understand when the closure is created in the component lifecycle and use the stable function instead of unstable state variables within Hooks.
Note: Unlike the setState method found in class components, useState does not automatically merge update objects. You can replicate this behaviour by combining the function updater form with object spread syntax:
React also provides Context API to share data that can be considered "global" for a tree of React components, such as the current authenticated user, theme, or preferred language.
The key feature of React is the composition of components. Components written by different people should work well together. It is important to us that you can add functionality to a component without causing rippling changes throughout the codebase. (React Design Principles)
By extracting side effects from a React component, it becomes more predictable. You can expect the component to render the same output if the input is the same. In more specific words, it can gain referential transparency, or be idempotent.
In practice, the referential transparency should be assured by the static type checking and sufficient unit testing.
Static type checkers and linters, my preference is TypeScript and ESLint, make the development experience more confident and solid as they can identify certain types of problems before you even run your code.
Although the configuration could be a bit cumbersome when you start a new project, it helps you and your team to be much more productive. I don't see any reason not to use them in 2020.
A declarative component is easier to write the test as you can focus on the pure interaction and rendering of the component.
With Hooks, you can extract stateful logic from a component so it can be tested independently and reused. Hooks allow you to reuse stateful logic without changing your component hierarchy. (The motivation behind Hooks)
I believe that React Native Testing Library is now a defacto testing library for React Native. It integrates closely with Jest and provides clear testing methodologies along with the popular libraries such as React Navigation and Redux.
React Native Testing Library (or RNTL) is built on top of React Test Renderer. It adds useful APIs such as to render ( to getByText, queryAllByA11yRole, …), fireEvent, waitFor, and act. It is opinionated to focusing on user experience and accessibility.
React Hooks Testing Library to write test custom hooks that are not directly tied to a component or complex that is difficult to test through component interactions.
I understand that there has been and will be always a debate between React Native vs Native App development.