React applications are built by little code blocks, that we name components. These components have a lifespan and important points in life, just like us humans. They are born (created), they live (show up on the screen, and do whatever they're supposed to do), they change and grow (re-render if the component state changes) and at some point, they die (get removed from the DOM, their content is removed from the screen).
The lifecycle methods of a component are functions that are called in specific times of a component's life. These functions are provided by React, and they are empty by default. Only if you decide to implement one of these methods, they will change something.
Think of a function that runs every time you learn something new. By default, this function does nothing. But, if your creator added a "chinggg" sound to this function, each time you learned something new, you would hear a "chinggg" in your head. It would be a lifecycle method defined just for you (to drive you crazy, probably).
There are two groups of lifecycles. One is the creation lifecycle (the one that runs only when an instance of a component is created), the other one is the update lifecycle (this runs whenever the state of the component is updated).
When the state of a component changes, it will force a react component to run through the update lifecycle, which will call the methods following, in respect:
Before React version 16.8, class-based components were 'stateful' and function-based components were 'dumb' or 'stateless'. In version 16.8, hooks were introduced to React, which made implementing lifecycle methods and other functionalities with function-based components possible. They're named hooks because these are built-in functions that help you hook a certain functionality to your function-based components. Most basic hooks are useState, useEffect, useRef, and useContext, which deserve their own article and will not be discussed in this one.
A PureComponent is a normal component that automatically implements shouldComponentUpdate with a complete props and state check. If nothing has changed, there is no need to re-render the component, so it will save you from unnecessary renders.
There are two disadvantages to using PureComponent. The first one is the shallow comparison, if you're using complex data structures as props and states, you can have bugs. The other disadvantage is that it skips prop updates for the children components of the PureComponent, si the whole subtree of a PureComponent has to be PureComponent's as well.
You can extend PureComponent instead of Component after importing it, and it will change the component into a PureComponent.
The render method or anything that is returned with the function components does not automatically re-render the real DOM.
Accessing the DOM is slow. So you need to prevent it as much as you can.
React takes another approach, which is initially updating the virtual DOM because it is faster and more efficient. Virtual DOM is a simple representation of the UI (a lightweight copy of the real DOM) kept in memory. It is not a specific technology but a pattern to update the user interface. Updating the virtual DOM causes no changes on the screen.
At a given time, React keeps two copies of the DOM. One is the old virtual DOM (actually a snapshot of it), and the second one is the new, re-rendered virtual DOM. It compares the old virtual DOM to the new one, and it checks if there are any differences. React traverses the DOM tree in a breadth-first manner, (meaning working from top to bottom and left to right) and if there is a modification, the whole subtree will be rendered (unless you are using PureComponent). The real DOM will be synced with the modified subtrees of the virtual DOM using a DOM manipulation library, such as ReactDOM. Changes on the real DOM causes changes on the screen.