React is a library by Facebook that allows you to create super performant user interfaces. React allows you to disintegrate a user interface into components, a functional unit of an interface. By composing components together, you can create UIs that scale well and deliver performance.
What sets React apart is its feature set.
1. The Virtual DOM - An in-memory representation of the DOM and a reconciliation algorithm that is at the heart of React’s performance.
2. Declarative Programming & State - State is the data that describes what your component renders as its content. You simply update the state and React manages the rest of the process that leads to the view getting updated. This is known as declarative programming where you simply describe your views in terms of data that it has to show.
3. Components - Everything that you build with React, is known as a component. By breaking down UIs into functional and atomic pieces, you can compose together interfaces that scale well. The image below demonstrates a login interface which has been composed together using three components.
4. JSX - The render method inside a class component or the function component itself allows you to use JSX, which is like an XML language that incorporates JavaScript expressions. Internally, JSX is compiled into efficient render functions.
5. Synthetic Events - Browsers handle events differently. React wraps browser specific implementations into Synthetic Events, which are dispatched on user interaction. React takes care of the underlying browser specific implementation internally.
6. Props - Components can either fetch data from an API and store in the local state, or they can ingest data using props, which are like inlets into a prop. Components re-render if the data in the props update.
On 26th September, 2017, React 16.0 was announced with much fanfare. It was a major leap forward in the evolution of React and true to its promise, the 16.x branch has marched on, conquering new heights and setting benchmarks for the library, the developer experience,and performance.
So, let’s look back at the 16.0 branch, right from its inception and analyze its evolution, all the way to React 16.8.
Released: 26th September, 2017
React 16.0 marked a major leap forward in the evolution of the library and was a total rewrite. Some of the major features introduced in this release include:
Code Example :
import React, { Component } from 'react'; import { render } from 'react-dom'; const FruitsList = props => props.fruits.map((fruit, index) => <li key={index}>{fruit}</li>); class App extends Component { constructor() { super(); this.state = { fruits: ["Apple", "Mango", "Kiwi", "Strawberry", "Banana"] }; } render() { return ( <ul> <FruitsList fruits={this.state.fruits} /> </ul> ); } } render(<App />, document.getElementById('root'));
The <FruitsList /> component in the example above simply renders an Array of list items with keys and without an enclosing element at the root. This saves an extra and unwanted element from being rendered in the DOM.
Code Example:
import React, { Component } from 'react'; import { render } from 'react-dom'; const App = () => 'This is a valid component!'; render(<App />, document.getElementById('root'));
Code Example :
import React, { Component } from 'react'; import { render } from 'react-dom'; class ErrorBoundary extends Component { state = { error: false } componentDidCatch(error, info) { this.setState({ error: true }); } render() { if (this.state.error) { // You can render any custom fallback UI return <h1>There was an Error!</h1>; } return this.props.children; } } class DataBox extends Component { state = { data: [] } componentDidMount() { // Deliberately throwing an error for demo purposes throw Error("I threw an error!"); } render() { return 'This App is working!' } } const App = () => <ErrorBoundary><DataBox /></ErrorBoundary> render(<App />, document.getElementById('root'));
Code Example :
import React, { Component } from 'react'; import { render, createPortal } from 'react-dom'; import "./style.css"; const Notice = () => createPortal('This renders outside the parent DOM node', document.getElementById("portal")); class App extends Component { render() { return ['Renders in the root div', <Notice />] } } render(<App />, document.getElementById('root'));
Version | Release Date | Features added in the release |
---|---|---|
16.1 | 9th November, 2017 |
|
16.2 | 28th November, 2017 |
|
16.3 | 29th March, 2018 |
|
16.4 | 23rd May, 2018 |
|
16.5 | 5th September, 2018 |
|
16.6 | 23rd October, 2018 |
|
16.7 | 19th December, 2018 | React 16.7 was a small release with a few bug fixes and performance enhancements in the React DOM package. |
React 16.8 marks a major step forward in React and the way developers can implement function components and use React features.
React was built by Facebook to solve real and practical challenges that the teams were facing with Facebook. As a result, it was already battle-tested before release. This and the continuous and progressive development of React has made it the library of choice for companies worldwide. Facebook itself maintains a huge code base of components ( ~50K+ ) and is a big reason why new features are gradually added without sudden deprecations or breaking changes.
All of these factors contribute to an industry grade library. It is no wonder that interest for React has grown tremendously over the past 3+ years. Here’s a Google Trends graph demonstrating React’s popularity when compared to Angular, over the past 3 years.
Some of the big & popular names using React in production include:
AirBnb | American Express | Air New Zealand |
Algolia | Amazon Video | Atlassian |
Auth0 | Automattic | BBC |
Bitly | Box | Chrysler.com |
CloudFlare | Codecademy | Coursera |
Dailymotion | Deezer | Discord |
Disqus | Docker | Dropbox |
eBay | Expedia | Facebook (Obviously) |
Fiatusa.com | Fiverr | |
Flipkart | Free Code Camp | Freecharge |
Grammarly | Hashnode | Housing.com |
HubSpot | IGN | IMDB |
Imgur | Intuit | |
Jeep.com | Khan Academy | Magic Bus |
Monster India | NHL | Naukri.com |
NBC TV Network | Netflix | New York Times |
NFL | Nordstrom | OpenGov |
Paper by FiftyThree | PayPal | Periscope |
Postman | Practo | Rackspace |
Ralph Lauren | Recast.AI | |
Reuters TV | Salesforce | Shure UK |
Skyscanner | Spotify Web Player | Squarespace |
Treebo | TuneIn Radio | Twitter - Fabric |
Uber | Udacity | Walmar |
WhatsApp for Web | Wix | Wolfram Alpha |
WordPress.com | Zapier | Zendesk |
This is of course a small list, compared to the thousands of sites and apps that are built using React and its ecosystem of products.
React 16.8 added the incredible Hooks API, giving developers a more direct and simpler way to implement React features such as state and lifecycle methods in function components, without the need to build or convert function to class components. In addition to these abilities, the API is extensible and allows you to write your own hooks as well.
Hooks is an opt-in feature and is backward compatible. And while it offers a replacement to class components, their inclusion does not mean that class components are going away. The React team has no plans to do away with class components.
As the name implies, Hooks allows your function component to hook into React features such as state and lifecycle methods. This opens up your components to a number of possibilities. For instance, you can upgrade your static function component to include local state in about 2 lines of code, without the need to structurally refactor the component in any form.
Additionally, developers can write their own hooks to extend the pattern. Custom hooks can use the built-in hooks to create customised behaviour which can be reused.
The Hooks API consists of two fundamental and primary hooks which are explained below. In addition to these fundamental hooks, there are a number of auxiliary hooks which can be used for advanced behaviour. Let’s examine these, one by one.
useState : The useState hook is the most fundamental hook that simply aims to bring state management to an otherwise stateless function component. Many components written initially without local state in mind, benefit from easy adoption of state without refactoring needed.
The code below is a simple counter which started off as the following basic component:
Before Using Hooks
const App = ({count}) => (<h1>{count}</h1>);
To turn this into a stateful counter, we need two more ingredients:
Let’s say we have buttons in place, to bring the state variable to life, we can use the useState() hook. So, our simple <App> component changes as follows:
After using the useState() Hook
const App = () => { const [count, setCount] = useState(0); return ( <> <h1>{count}</h1> <button onClick={() => setCount(count + 1)}>Increment</button> <button onClick={() => setCount(count - 1)}>Decrement</button> </> ); }
The statement const [count, setCount] = useState(0) creates a local state variable named “Count” with an initial value of 0, as initialized by the useState() method. To modify the value of the “Count” variable, we’ve declared a function called “setCount” which we can use to increment or decrement the value of the “Count” variable.
This is really simple to understand and works brilliantly. We have two buttons named Increment and Decrement and they both invoke the “setCount()” method which gets direct access to the “count” variable to update directly.
Code Example on (StackBlitz) :
import React , {useState} from 'react'; import { render } from 'react-dom'; import "./style.css"; const App = () => { const[count, setCount]= useState(0); return( <> <h1>{count}</h1> <button onClick={()=> setCount(count +1)}>Increment</button> <button onClick={()=> setCount(count -1)}>Decrement</button> </> ); } render(<App />, document.getElementById('root'));
useEffect : The useEffect hook enables a function component to implement effects such as fetching data from an API, which are usually achieved using the componentDidMount() and the componentDidUpdate() methods in class components. Once again, it is important to iterate that hooks are opt-in which is what makes them flexible and useful.
Here’s the syntax for the useEffect() hook:
const App = () => { const [joke, setJoke] = useState("Please wait..."); useEffect(() => { axios("https://icanhazdadjoke.com", { headers: { "Accept": "application/json", "User-Agent": "Zeolearn" } }).then(res => setJoke(res.data.joke)); },[]); return (<div className="joke">{joke}</div>); }
Code Example:
import React , {useState, useEffect} from 'react'; import { render } from 'react-dom'; import "./style.css"; import axios from "axios"; const App = () => { const[joke, setJoke]= useState("Please wait..."); useEffect(() => { axios("https://icanhazdadjoke.com", { headers: { "Accept":"application/json", "User-Agent":"Zeolearn" } }).then(res => setJoke(res.data.joke)); },[]); return(<div className="joke">Dad says,"{joke}"</div>); } render(<App />, document.getElementById('root'));
The code above fetches a random dad joke from the “icanhazdadjoke.com” API. When the data is fetched, we’re using the setJoke() method as provided by the useState() hook to update the joke into a local state variable named “joke”. You’ll notice the initial value of “joke” is set to “Please wait…”.
This will render right away while useEffect() runs and fetches the joke. Once the joke is fetched and the state updated, the component re-renders and you can see the joke on the screen.
But behind all this, there is an important caveat. Note the second argument to the useEffect() function, an empty array. If you remove this array, you’ll get a weird problem where the component keeps re-rendering again and again and you see a new joke update repeatedly. This happens because unlike componentDidMount(), useEffect() runs both on mount and update, so whenever a component re-renders, the hook runs again, updates, re-renders and the process repeats.
To stop this behaviour, a second argument, an Array may be passed as shown above. This array should ideally contain a list of variables which you need to monitor. These could also be props. Whenever the component re-renders, the state or prop mentioned in the array is compared with the previous value and if found same, the component doesn’t re-run the hook. This also happens when there is nothing to compare, as in the case of a blank array, which is what we’ve used here. This is, however, not the best of practices and may lead to bugs since React defers execution of the hook until after the DOM has been updated/repainted.
The useEffect() function can also return, which is somewhat equivalent to componentWillUnmount() and can be used for unsubscribing from publisher-subscriber type APIs such as WebSockets.
Besides the above two hooks, there are other hooks that the API offers:
useReducer : If you’ve ever used Redux, then the useReducer() hook may feel a bit familiar. Usually, the useState() hook is sufficient for updating the state. But when elaborate behaviour is sought, useReducer can be used to declare a function that returns state after updates. The reducer function receives state and action. Actions can be used to trigger custom behaviour that updates state in the reducer.
Thereafter, buttons or other UI elements may be used to “dispatch” actions which will trigger the reducer.
This hook can be used as follows:
const [state, dispatch] = useReducer(reducer, {count: 0});
Here, reducer is a function that accepts state and action. The second argument to the useReducer function is the initial state of the state variable.
Code Example :
import React , {useReducer, useEffect} from 'react'; import { render } from 'react-dom'; import "./style.css"; import axios from "axios"; const reducer = (state, action) => { switch(action.type){ case'ticktock': return{ count: state.count +1}; case'reset': return{ count:0}; } } const timer; const App = () => { const[state, dispatch]= useReducer(reducer,{count:0}); return( <> <h1>{state.count}</h1> <button onClick={()=>{ timer = setInterval(() => dispatch({ type: 'ticktock' }), 1000); }}>Start</button> <button onClick={()=>{ clearInterval(timer); dispatch({ type: 'reset' }); }}>Stop&Reset</button> </>); } render(<App />, document.getElementById('root'));
In the code example above, we have a reducer function that offers two state, “start” and “reset”. The “start” action simply increments the count by 1, while “reset” sets it to 0.
The Start button then instantiates a setInterval timer that keeps dispatching the “start” action, which keeps incrementing the count every second.
The Reset button clears the timer and dispatches the “reset” action which resets the count back to 0.
useReducer is best used when you have complex state logic and useState is not enough.
Here’s a summary of other available hooks in the v16.8 release:
useCallback : The useCallback hook enables you to implement a memoization enriched callback function which enables an equality check between a function and inputs, to check if renders should be performed. This is equivalent in concept to the shouldComponentUpdate function that the PureComponent allows you to implement.
useMemo : This hook enables you to pass in a function and an array of input values. The function will only be recomputed if the input values change. This, like the useCallback, enables you to implement equality check based optimizations and prevent unwanted renders.
useRef : This hook is useful for accessing refs and initializing them to a given value.
useImperativeHandle : This hook enables you to control the object that is exposed to a parent component when using a ref. By using this hook, you can devise custom behaviour that would be available to the parent using the .current property.
useLayoutEffect : This hook is similar to the useEffect hook but it is invoked synchronously after the DOM has been mutated and updated. This allows you to read elements from the DOM directly. As a result, this can block updates and hence should ideally be avoided.
useDebugValue : This hook is used to display a custom label for hooks in the React DevTools.
To summarize, v16.8’s revolutionary, Hooks API opens the door to a whole new way of developing React components.
Upgrading to v16.8 is a relatively simple affair, mainly because it doesn’t introduce breaking changes unless you’re on a very old branch. Team React ensures that incremental upgrades do not introduce sudden API changes or breaking changes that would cause an app to crash or behave erratically.
Likewise, if you’re anywhere on the 16.0 branch already, you can conveniently upgrade to 16.8.x by either downloading and installing both react and react-dom packages using npm or yarn, or using the CDN links to unpkg.com, as listed here https://reactjs.org/docs/add-react-to-a-website.html
If you’ve used create-react-app to setup your React project, then you can edit the package.json to upgrade versions of react-scripts, react and react-dom to their latest versions before running npm install to download and upgrade the packages.
A product’s future depends on how well it is embraced by consumers. Many products are built first and attempts are made to entice developers to create a demand. React isn’t one of those frameworks. It was born from the kiln of production at Facebook and it powers more than 50 thousand components and more growing every day. And besides Facebook, React now empowers thousands of companies to write and design scalable UIs that are highly performant with a fantastic developer experience.
It is thus, quite natural that the team at Facebook is hard at work, developing the next cutting edge edition of React. Over the years, a vibrant and global community of React developers have sprung up and they’re actively contributing to the ecosystem, in much the same fervour as seen during the days of jQuery.
With that said, React is poised to take a leap forward. React 16.x has paved the way for the future by introducing the “Fiber” reconciliation engine and a slew of super cool features such as Context, Hooks and the Suspense API.
Going forward, React’s next big feature will land in Q2 of 2019. Concurrent Rendering would allow React to prioritize updates such that CPU usage is optimised for high-priority tasks first, thereby massively improving the user experience.
Another feature that is expected to land later in 2019 is Suspense for Data Fetching. This API will allow components to display a fallback UI if asynchronous data fetching is taking more time than a prescribed limit. This ensures that the UI is responsive and displays indicators for the user to understand data fetch latencies in a better way.
To summarize, React 16.x is going to get a whole lot better before the leap to v17.
The team at Facebook have done a commendable job with React. Their commitment to improving the user experience as well as the developer experience is seen by the incredible array of features that are released from time to time. Whether it is the Context API, or Hooks or the upcoming concurrent rendering, React is the battle-tested weapon of choice for building your next winning site or even a mobile app!
Leave a Reply
Your email address will not be published. Required fields are marked *