The world of front-end development, particularly JavaScript, is constantly changing. The constant influx of new technologies and tools can be overwhelming, even for experienced developers. Sometimes, it’s comforting to have a reliable and stable solution amidst all the flux. React, a JavaScript library for building user interfaces, has emerged as such a haven.
This multi-part React tutorial will delve into React’s capabilities and compare it with other popular frameworks like Angular and VueJS.

While other suitable options exist, React currently stands out as one of the most popular, stable, and innovative solutions available. Though it still receives upgrades, they are usually optional improvements rather than essential updates.
React’s Journey in 2019
React’s origins can be traced back to 2011 with the appearance of its prototype, FaxJs, on Facebook. Jordan Walke, who also authored the prototype, officially introduced React at JSConfUS on May 29, 2013. The library was then open-sourced on GitHub on July 2, 2013.
React’s popularity soared in 2014 as conferences dedicated to its growth and promotion emerged. However, 2015 marked a turning point for React, with major companies like Airbnb and Netflix embracing its solutions. Additionally, React Native was released that year. Though not entirely novel, the concept behind React Native, particularly with Facebook’s backing, drew considerable interest.
Another significant development was the introduction of Redux, a Flux implementation that simplified state management, making it the most successful approach to date.
Numerous advancements followed, including React tools, a revamped core algorithm (Fiber), a shift to semantic versioning, and more. Today, React stands at version 16.6.3, with the release of a new version featuring Hooks anticipated soon (initially planned as 16.7.0 but already released as 16.7.0 with fixes for React.lazy). React has earned a strong reputation as a well-established and stable library.
Defining React
If you’re a front-end developer unfamiliar with React, congratulations are in order—that’s quite an accomplishment!
In all seriousness, React is a declarative, component-based view library that facilitates UI development. It’s crucial to understand that React is a library, not a framework, though it’s often misconstrued as the latter.
While incorporating Redux, React Router, and other tools can transform React into a comprehensive single-page application framework, React, in its essence, remains a library. The “framework” label might be considered more fitting when encompassing the entire ecosystem of tools, but React itself is a library.
Moving beyond terminology, let’s explore React’s distinctive features that set it apart from its predecessors. One of the first things that come to mind with React is JSX, a prominent aspect when examining React code. JSX is a JavaScript syntax extension that shares similarities with HTML/XML. However, there are subtle differences between React and HTML. For instance, a class in React is className, tabIndex replaces tabindex, style attributes accept camelCased JavaScript objects, and so on.
These minor discrepancies are easily grasped. Event handling is accomplished through attributes like onChange and onClick, which can trigger functions to handle events. Additionally, components can be readily reused and tailored using props, eliminating the need for redundant code.
| |
Interestingly, JSX is not mandatory in React. Elements can be created using regular functions without relying on JSX. The same code demonstrated earlier can be written as follows:
| |
While I don’t recommend this syntax for general use, it can be handy in certain situations, such as when incorporating a small element without modifying the build environment.
The previous snippet also highlights why the following import is necessary:
| |
Despite extracting the Component, React is still required because Babel transpiles the JSX code into React.createElement calls. Without importing React, the code would fail.
Babel is a tool that enables the use of features not yet present in JavaScript (or rather, browsers), extends JavaScript syntax, and even supports different languages like TypeScript (from Babel 7 onwards). Babel facilitates:
- Converting JSX into browser-compatible functions.
- Leveraging new JavaScript features that are not yet widely supported.
- Maintaining support for older browsers while incorporating features from newer ones.
In essence, Babel brings the future of JavaScript to the present. This topic deserves its own dedicated article. While the React import can be circumvented using techniques like Webpack’s ProvidePlugin, we’ll assume the use of Create React App (CRA) for brevity.
Another crucial aspect of React, even more significant than JSX, is its foundation on the virtual DOM. In simple terms, the virtual DOM is an in-memory representation of the ideal DOM tree, created using JavaScript. This virtual DOM is then compared to the actual DOM, and any differences are synchronized through a process called reconciliation.
Comparing React with Angular and Vue
Comparing libraries, especially when they’re fundamentally different (libraries vs. frameworks), can be misleading.
Instead of contrasting React with Angular and Vue based on subjective preferences like JSX versus templates, I’ll address a series of short questions. Metrics like speed and memory allocation are quite similar among React and its major competitors (Angular and Vue). While a particular good report on the matter exists, it’s essential to note that most applications don’t resemble massive tables requiring rapid row swaps. These benchmark results are purely experimental; such scenarios are uncommon in real-world applications.

Let’s delve into some relevant questions regarding React and its competition:
For ample job opportunities, how popular is React?
React is the clear winner here. Job openings for React developers outnumber those for Vue by roughly 6-10 times (though the ratio varies across platforms, ranging from 1:50 to 1:6) and surpass Angular openings by 2-4 times. Given the high demand for React expertise, it’s intriguing that Vue, despite having more GitHub stars, has fewer job postings.
For a large community, abundant libraries, and readily available solutions, which is best?
React, without a doubt.
Which option offers ease of use and an enjoyable development experience?
According to the State of JS reports for 2018 and 2017, React and Vue receive overwhelmingly positive feedback, with most developers expressing a willingness to use them again. On the other hand, Angular consistently receives a higher percentage of developers who would not choose it again.
To create a single-page application without searching for libraries, which should I pick?
This is perhaps the only scenario where Angular might be the superior choice.
For maximum independence from large corporations, which option is best?
Vue is the only independent option among the three (React is backed by Facebook, and Angular is supported by Google).
Which has the easiest start and fastest learning curve?
Both Vue and React are contenders here, though my personal preference leans slightly towards Vue.
Why? Because JSX is optional in Vue, and it essentially boils down to HTML, CSS, and JavaScript.
React Tutorial: Building Your First App

Using CRA is currently the most straightforward way to initiate a React project. This CLI tool sets up a project with pre-configured Webpack/Babel settings and other dependencies, saving you the hassle of manual configuration. This approach eliminates the need to worry about major updates for critical libraries.
You can always “eject” from CRA later and manage every aspect independently by running npm run eject. While this grants you greater control and the ability to integrate features like decorators, it can also lead to complexities and require extensive configuration.
To begin:
| |
Then, run npm run start, and you’re all set!
Class Components vs. Function Components
Let’s clarify the distinction between these component types. Essentially, every component can be defined as a function or a class. The key difference lies in the additional features that class components offer, such as state management, refs, and lifecycle methods—features not available in function components.
Currently, this distinction holds true. However, with the introduction of hooks in version 16.7 (or its final version name), state management and refs will also be possible within function components.
There are two categories of class components: Component and PureComponent. The sole difference is that PureComponent performs a shallow comparison of props and state. This proves beneficial when you want to avoid unnecessary renders if a component and its children remain in the same state after a render. However, keep in mind that this comparison is shallow. If you need custom comparison logic (e.g., when passing complex props), use Component and override the shouldComponentUpdate method (which defaults to returning true). Since version 16.6, function components have gained similar functionality through React.memo, a higher-order component that behaves like PureComponent by default (shallow comparison). It also accepts a second argument for passing a custom props comparison function.
As a rule of thumb, opt for function components unless you specifically require class component features. With the release of version 16.7.0, the primary reason to use class components will be for lifecycle methods. Function components are often considered more transparent, readable, and easier to reason about.
React Lifecycle Methods

Constructor(props)
- Optional, particularly with the prevalence of CRA, which includes class field declarations by default. It’s unnecessary if you’re using arrow functions to bind methods within the class or initializing state as a class property.
- Primarily used for initializing local state objects and binding methods in ES6 classes.
componentDidMount()
- Suitable for making AJAX calls.
- Ideal for setting up event listeners, subscriptions, and similar tasks.
setStatecan be used here (though it will trigger a re-render).
componentWillUnmount()
- Cleans up ongoing operations—interrupt AJAX calls, unsubscribe from subscriptions, clear timers, and so on.
- Avoid calling
setStatehere as it’s redundant (the component will be unmounted anyway) and will trigger a warning.
componentDidUpdate(prevProps, prevState, snapshot)
- Triggered after a component finishes updating (excluding the initial render).
- Takes three optional parameters: previous props, previous state, and a snapshot (available only if your component implements
getSnapshotBeforeUpdate). - Executes only if
shouldComponentUpdatereturns true. - Use
setStatecautiously here; protect it with guards to prevent infinite loops.
shouldComponentUpdate(nextProps, nextState)
- Intended for performance optimization.
- Returning false prevents a re-render.
- Consider using
PureComponentif your overriddenshouldComponentUpdateperforms only a shallow comparison of props and state.
getSnapshotBeforeUpdate()
- Useful for capturing information about the current DOM (e.g., scroll position) that can be reused within
componentDidUpdate(e.g., to restore scroll position).
componentDidCatch(error, info)
- Appropriate for error logging.
- Can call
setState, but this will be deprecated in favor of the static methodgetDerivedStateFromError(error), which will update state by returning a value.
Two additional static methods were mentioned earlier:
static getDerivedStateFromError(error)
- Provides access to error information.
- Should return an object to update the state for error handling (e.g., displaying an error message).
- Being static, it lacks access to the component instance.
static getSnapshotBeforeUpdate(props, state)
- Useful when props change over time, such as in a transition component (as per React documentation).
- Being static, it lacks access to the component instance.
Note that some other lifecycle methods are currently available but are slated for removal in React 17.0, hence their omission here.
State vs. Props
Let’s start with Props, the simpler of the two. Props are properties passed to a component, which can then be used internally for displaying data, implementing logic, and more.
| |
In this example, name is a prop. Props are read-only and cannot be modified directly within child components. One common anti-pattern is copying props to state and then operating on the copied state. While there are cases where this might be necessary (e.g., initializing state that updates the parent component after submission), such situations are rare. In general, avoid copying props to state unless absolutely necessary.
Props also have a helpful feature called defaultProps, a static field that specifies the default values for props (used when no values are explicitly passed).
When “lifting state up”—a pattern where a parent component manages state that is used by its children (e.g., one child displays the state, and another allows editing)—you pass a function from the parent to the child. This function enables the child to update the parent’s local state.
In contrast, State represents a component’s internal, mutable state. However, state modifications should be made indirectly using this.setState. Directly mutating the state will not trigger a re-render, leaving the component unaware of the changes.
SetState is a method for modifying the local state object (via a shallow merge). After calling setState, the component re-renders to reflect the state changes. It’s crucial to understand that this.state won’t immediately reflect the changes made within setState due to its asynchronous nature. Multiple setState calls might be batched together for optimization purposes.
setState can be invoked in a few ways, with one option allowing you to execute code after the state update:
setState({value: ‘5’})setState((state, props) => ({value: state.name + “‘s”}))setState([object / function like above], () => {})– This form accepts a callback function as the second argument, which is executed after the state update.
| |
React Context
React recently stabilized the Context API (previously an experimental feature despite widespread adoption in libraries like Redux), addressing the issue of “props drilling.” Props drilling refers to passing props down through multiple levels of components, often for sharing data like themes, localization settings, user information, etc. Before Context (or its non-experimental status), this was typically handled by passing props recursively from parent to child, down to the desired component (Redux also provided a solution). Remember that Context specifically solves props drilling and isn’t a replacement for state management libraries like Redux or Mobx. If you were solely using a state management library for props drilling, then Context is a suitable replacement.
Conclusion
This concludes the first part of our React tutorial. In the upcoming parts, we’ll explore more advanced topics, such as styling, type checking, production deployment, and performance optimization.