React ~ Architecture - rohit120582sharma/Documentation GitHub Wiki

React is not a full MVC framework and used to manage specific parts of an application's UI and not others. React provides a virtual DOM implemented entirely as JavaScript classes. React will periodically diff the virtual DOM against the browser DOM, and make the minimal set of changes needed to bring the browser DOM into sync.

Props

Any data that is passed to a component as part of it’s creation is classed as props. The data flows from the top downwards, ie. from parent to child. If a parent passes new props to an existing child this will trigger the child to re-render. The props are saved for reference throughout the life of the component but the component itself does not have the power to change them.

State

Any data that a component decides to store within itself is it’s state. State is the sanctuary over which a component can retain complete control. Every time a component’s setState() function is called, it performs the dual actions of both updating the state, and re-rendering the component.

References



Application Architecture

React really forces you to think carefully about the structure of your app, as both data (in the form of props and state) and control flows in a very linear way between parents and children.

Let's understand each area of this architecture:

React Views

React has become the most preferred choice when it comes to writing client side JavaScript applications. It’s code re-usability, writing code in JSX and virtual DOM has made react popular and easy to work with. React Views makes a request for action based on interactions on/with the application. A React component can contain local state, but we avoid this. A functional (stateless) React component will always render the same UI given the same props. By keeping the state in Redux, we can always produce the same UI state given the same store contents.

Store and Immutable.js

Store is a single object that holds the complete state of your application. It delegates the reducer with the responsibility of changing state when an action is dispatched. We use Redux which is a library that controls the state of our application. It provides a “unidirectional data flow” that helps to manage and organise data better and makes debugging a lot easier.

We're also using "immutable.js" which is efficient data structure library providing immutable Lists, Maps and more. It relies on structural sharing to reduce memory footprint while staying immutable. It's cheap to determine if a component needs to re-render because Immutable data structures cannot be mutated.

Saga

It is a Redux middleware for handling async operations like fetching data from Fusion Production APIs. It makes asynchronous operations look like standard Javascript synchronous code making it easy to read, test, and reason.

Action handlers

It's commonly called action creator which returns a formatted object of the action type and optional payload. They are passed via the Middlewares to the Reducers.

Reducers

They are simply pure functions whose purpose in life is to accept the state tree and an action from the store; make a copy of the previous state, transform it and then return a new state to the store.

Selectors

We use selectors to:

  • Reduce the complexity of reducers & components
  • Decouple the rest of app from your state shape
  • Obey the single source of truth principle, even within reducer


UI Components



Dealing with data

Redux is a great pattern for centralizing state management with immutable data structures. This concept is called "Single Source of Truth".

One of the primary benefits of Redux is that application state is contained in a single source of truth, with data stored in a normalized structure. Normalized state structure generally implies that more components are connected and each component is responsible for looking up its own data, as opposed to a few connected components looking up large amounts of data and passing all that data downwards. As it turns out, having connected parent components simply pass item IDs to connected children is a good pattern for optimizing UI performance in a React Redux application, so keeping state normalized plays a key role in improving performance. We're using JSON API normalizer library to transform data we get from API into normalized state. It helps awesome JSON API and Redux work together. Unlike normalizr, json-api-normalizer supports JSON API specification, which means that we don't have to care about schemes. It also converts collections into maps, which is a lot more suitable for redux.

Redux object library, which works best with json-api-normalizer, it helps to build complex JS object from normalized redux store.



Routing

We're using react-router-redux library which helps to keep bit of state in sync with Redux store. It keeps a copy of the current location hidden in state. When we rewind your application state with a tool like Redux DevTools, that state change is propagated to React Router so it can adjust the component tree accordingly. We can jump around in state, rewinding, replaying, and resetting as much as we'd like, and this library will ensure the two stay in sync at all times.



Internationalization & Localization

Internationalized web application provides a great user experience for people everywhere around the work and it is very crucial for our product as well. We need to not only support multiple languages but need to create a sustainable workflow so that new translations can be added easily and integrated into the developer experience without being cumbersome.

We're using react-localize-redux library to achieve it.



Testing

We're using Jest (Read about it here) because:

  • We wanted some framework which could be easily setup and start testing. i.e spend minimum time to setup the framework for our project.
  • Ability to run tests in parallel. For a huge app like us with lot of tests, it will be quick if the tests could run in parallel.
  • Snapshot testing. This is a really cool feature which helps to reduce number of tests we have to write as we just create a snapshot and if anything changes in our components, we will get an error when the snapshot is generated the next time.
  • Jest uses Jasmine for assertion which is easy to write tests.
  • Code coverage is available right out of the box and it can be integrated as a part of CI/CD pipeline by simply passing required jest coverage parameter.
  • In-built Manual mocking
  • Awesome interactive watch mode that reruns only tests that are relevant to your changes.
  • Helpful fail messages.
  • Simple configuration.

We're also using Enzyme which is testing utility for React for below reasons:

  • Convenient utilities to work with shallow rendering, static rendered markup or DOM rendering.
  • jQuery-like API to find elements, read props, etc.

Here are the libraries which we use along with jest:

  • babel-jest  — To support ES6 and ES7 for our tests.
  • enzyme — JS testing utility developed by Airbnb to make it easier to assert React Components.
  • react-addons-test-utils — Provides the React TestUtils which we won’t use directly but it is required as a dependency to enzyme.
  • react-test-renderer — Used to grab snapshot of DOM tree rendered by React DOM/ React Native components
  • redux-mock-store — Used to mock our Redux store.


Bundling

We're using webpack as it's a great module bundle tool and widely adopted by the React community.



⚠️ **GitHub.com Fallback** ⚠️