As the React official website states:
We design efficient cool single page applications using React.
Any web page can be divided into components. An example:
UI state becomes difficult to handle with Vanilla JS. You have to manually target DOM elements and chances are, you will end up using too many query selectors for your manipulations and operations.
When we are creating web-apps where we dynamically add or remove components, this can be a cumbersome operation with Vanilla JS.
React saves us from this nightmare, the UI state management issue. It allows developers to focus on business logic, instead of focusing on preventing the app from exploding.
React is maintained by a big community, which is an added advantage.
It is a syntax extension to JS. Babel compiles JSX down to React.createElement() calls.
So, above two examples are identical.
NOTE: JSX prevents injection attacks.
By default, React DOM escapes any values embedded in JSX before rendering them. Thus, it ensures that you can never inject anything that’s not explicitly written in your application.
Instead of artificially separating technologies by putting mark-up and logic in separate files, React separates concerns with loosely coupled units called “components” that contain both.
Rendering in React
Usually, a SPA built in react will have a single root DOM node. As mentioned on official website,
“Elements are the smallest building blocks of React apps”.
What we see on screen is an element. And to render a React element on to root DOM node, we use ReactDOM.render() method.
ReactDOM.render(<App />, document.getElementById(‘root’));
React elements are immutable. Once created, its children or attributes cannot be changed.
React DOM compares the element and its children to the previous one, and only applies the DOM updates necessary to bring the DOM to the desired state.
Props & States
Props and States are core concepts of React. Changes in props and/or states trigger React to re-render a component and potentially update the DOM in browser.
‘props’ allow us to pass data from a parent component to a child component. A component must never modify its own props. Props are read-only.
All React components must act like pure functions with respect to their props.
State is used to change the component, or to say, state of component from within. Changes to state also trigger an UI update.
In suggested project architecture, States are maintained in higher level components (usually class-based components) and passed to as props to the lower level components, which are usually presentational components. Lower level components can’t directly edit state.
States in React are not modified directly. It is modified through a method called ‘setState()’.
States are assigned in constructor only. State updates might get asynchronous, hence, a form of the above method, which accepts a function, instead of an object is most preferred. The function receives previous state as first argument and props at the time update is applied as second argument.
NOTE: ‘setState()’ method merges the object provided with the current state. However, merging is shallow.
Managing states in Functional Components
Historically, States in react used to be maintained in Class based components. However, since, React 16.8, there is also a way to manage states in functional components, using useState() React hook.
useState() is a function which accepts an initial state and returns an array with exactly two elements. First element returned back will always be current state and second element will always be a function which allows us to update this state. For example:
Stateless vs Stateful components
Stateful component is a component which can be either a class-based component or a functional component but manages state.
You can use stateless components inside stateful components, and vice versa.
Class based vs Functional components
The main difference between these two components, after latest update to React is, Class based components extend React Component while functional components are normal functions which take props as arguments. They differ in their state management and life cycle hooks.
Component Life Cycle Hooks
It only applies to Class based components. Important life cycle hooks for a class-based component in React are listed below in the diagram. We will be dividing these life cycle hooks based on component creation and component update. React executes these hooks for us at different point of time.
Component Life cycle — Creation
‘getDerivedStateFromProps’ is a life cycle hook which was added after React 16.3, which is a static JS function, to sync states with prop changes for the component. Although, it will used in very rare scenarios.
Component Life cycle — Update
‘getSnapshotBeforeUpdate’ takes previous props and previous state and returns a snapshot object which can be configured. It is also used minimal, usually in scenarios such as, if we want to store last scrolling point of the user in a component, so that after UI update, we can restore the view to that particular scrolling point.
Life cycle hook equivalent for Functional components
With introduction of React hooks, functional components have become more powerful and now can manage states as well. Earlier, we investigated a ‘useState’ React hook. Here, we are going to investigate ‘useEffect’ React hook, which basically combines the functionality or use cases we can cover of all the class-based life cycle hooks in one React hook.
‘useEffect’ will run for every render cycle. Hence, it is ‘componentDidMount’ and ‘componentDidUpdate’ in one hook. However, it can be trickier to use. What if we want to put a HTTP request only at creation of component for the very first time?
‘useEffect’ takes a second argument as an argument to check when it has to perform its operations. So, when we pass an empty array as an argument, it tells React, it has no dependencies to check, hence, will be run only at time of creation.
‘shouldComponentUpdate’ life-cycle hook takes two arguments nextProps and nextState. It basically compares the nextProps with the current props, but it can be trickier.
Supposes, there is an array ‘persons’ on props and it has to be compared in this life cycle hook. Arrays are reference type in JS. Hence, mutation of states in React becomes important. We always create a new object which in turn refers to a new pointer and sub sequentially, comparison gets successful.
Since, this life-cycle hook is not available for functional component, we optimize our functional components using React.memo().
If we want to do a complete props check, it is better to use a Pure Component in React, rather than using this life-cycle hook.
DOM updates in React
React does not do DOM updates just after render method call. It compares Old Virtual DOM with Re-rendered DOM.
It only changes in places where differences are detected. For example, if a button text change, it will only update the text, not re-render the button, forget about the DOM.
Higher order Components
All it does essentially is, it wraps another component. It does not contain its own logic or styling or adds any structure to JSX code.
Refs provide a way to access DOM nodes or React elements created in the render method.
There are a few good use cases for refs:
· Managing focus, text selection, or media playback.
· Triggering imperative animations.
· Integrating with third-party DOM libraries
NOTE: Avoid using refs for anything that can be done via declaration.
I am also adding links to my related articles on Redux and comparison of change detection mechanism in Angular and React.
I would also like to mention Udemy course on React by Academind for making me understand nuances of React.