Latest Tutorials

Learn about the latest technologies from fellow newline community members!

  • React
  • Angular
  • Vue
  • Svelte
  • NextJS
  • Redux
  • Apollo
  • Storybook
  • D3
  • Testing Library
  • JavaScript
  • TypeScript
  • Node.js
  • Deno
  • Rust
  • Python
  • GraphQL
  • React
  • Angular
  • Vue
  • Svelte
  • NextJS
  • Redux
  • Apollo
  • Storybook
  • D3
  • Testing Library
  • JavaScript
  • TypeScript
  • Node.js
  • Deno
  • Rust
  • Python
  • GraphQL

    Fetching Data in a React Application with Axios

    Compared to frameworks like Angular, React is a library that only comes with functionality for state management and view rendering. With fewer tools baked into it, React requires additional, third-party libraries for handling important client-side features, such as routing, internationalization and sending HTTP requests to remote API endpoints. This unopinionated approach leaves the developer the responsibility of choosing these libraries to pair with React. For example, imagine you had to integrate an HTTP client library into your React application. You could write the HTTP client library from scratch using a low-level, imperative API like XMLHttpRequest . However, depending on the amount of time afforded, you might not have enough time to plan and develop the library to account for every possible use case. Alternatively, you could scour the NPM ecosystem for an open-source package that already supports the features you need along with other features you may need in the future. Just typing "http client" into the NPM search bar returns just under three thousand packages. Picking a specific package over other similar packages boils down to several factors, such as: For HTTP client libraries, choosing the Axios library likely makes sense for your React application. It is a popular, promise-based HTTP client with plenty of available configuration options for customizing HTTP requests. Additionally, Axios is isomorphic, which means it can run in both client-side (browser) and server-side (Node.js) environments. With tens of thousands of stargazers on GitHub , Axios's declarative API abstracts away low-level, networking implementation details and allows developers to focus more on the application code. Below, I'm going to show you how to fetch data in a React application with Axios. If you decide to use a native browser API to send HTTP requests to a server from your application, then there are two widely-used options: Many old browsers support the XMLHttpRequest object, but its imperative API is outdated by modern standards. To make AJAX calls with XMLHttpRequest , you must: Since it is not promise-based, XMLHttpRequest requires a wrapper function to create a promise-based API that utilizes XMLHttpRequest for the underlying implementation. Below, we wrap XMLHttpRequest within a sendRequest wrapper function that returns a promise capable of sending HTTP requests. That seems like a lot of code just to send an HTTP request! Fortunately, unlike XMLHttpRequest , the Fetch API is promise-based and boasts a more powerful and flexible feature set. Being promised-based, the Fetch API can make use of ES6 async / await syntax, which cleans up asynchronous code so it reads as synchronous code. However, the Fetch API has several downsides: With Axios, not only does it provide a promise-based API, but it also supports older browsers and comes with a plethora of useful features: Under-the-hood, the client-side version of Axios wraps around XMLHttpRequest while the server-side version of Axios wraps around the http module. To install Axios, run the following command: To import Axios into your project: To send HTTP requests with Axios, pass configuration options to the axios promise object: Or for convenience, use the request method alias .get for GET requests: Axios automatically provides a request method alias for each HTTP method: To use Axios with the async / await syntax... If you need to intercept requests before they are sent or responses before they arrive at the .then / .catch blocks, then use interceptors: Of course, we can cover more features of Axios, but this goes beyond the scope of this blog post. If you want to learn more about Axios and its other features, then check out the Axios documentation . Typically, data-driven React applications fetch data from a server and display this data to the user via an interactive data visualization. Data should be fetched once the component is mounted to the DOM. This allows us to immediately display a loading message to the user informing them to wait patiently as the data is being retrieved. Once the data is retrieved, then the component replaces the loading message with a data visualization. Render Loading Message → Fetch Data From Server → Render Data Visualization Therefore, within functional components, data fetching should take place within the useEffect hook, which performs side-effects, such as network requests, similar to the componentDidMount and componentDidUpdate lifecycle methods in class components. Within the useEffect hook: Because this data will only be fetched once, the useEffect hook will be passed an empty dependency array to ensure any state/prop changes don't retrigger the hook and refetch the data again. Inside of useEffect , we define an async function named fetchData that uses Axios to fetch data from a server located at a particular URL. Once the server returns the response, destructure out the data object from the response object and set the data state variable to this data object. If the request fails or times out, then Axios throws an error, which will be handled by the .catch block. To keep the example short and simple, this .catch block prints the error to the console of the developer tools. After setting the data state variable or handling the error, the isLoading state variable is set to false , which causes the component to render the <svg /> element in place of the <LoadingMessage /> component. Altogether... Try using Axios in your next React project!

    Thumbnail Image of Tutorial Fetching Data in a React Application with Axios

    Processing JSON with jq

    Commonly, we process JSON data by writing a program to load, deserialize and manipulate this data. Depending on the programming language, this program may require an additional compilation step before being executed within a terminal. For simple operations, such as filtering and mapping, we don't need to write an additional program to perform these operations on our JSON data. Rather, we can directly manipulate our JSON data within a terminal via the jq command-line utility, which allows the editing of streamed JSON data without an interactive text editor interface (" sed for JSON"). If you're looking for a tool to retrieve JSON data from an API endpoint, process this data and save the result to a CSV, TSV or JSON file, then jq easily accomplishes this task in a single-line command. Below, I'm going to show you how to process JSON data with jq . Install the jq command-line utility by visiting the homepage of the jq website, downloading a prebuilt binary (compatible with your operating system) and executing this binary once the download is complete. Alternatively... To verify the installation was successful, restart the terminal, and inside of this terminal, enter the command jq . This should print an overview of the jq command: For extensive documentation, enter the command man jq , which summons man ual pages for the jq command: To get started, let's pretty-print a JSON dataset (with formatting and syntax-highlighting). The jq command must be passed a filter as its first argument. A filter is a program that tells jq what output should be returned given the input JSON data. The most basic filter is the pre-defined identity filter . , which tells jq to do nothing to the input JSON data and return it as is. To run jq on a JSON dataset, pipe the stringified JSON to jq (e.g., the file content of a .json file via the cat command or the JSON response from an API endpoint via the cURL command). If we pipe the JSON response of a cURL command to jq . , then jq pretty-prints this response in the terminal. Suppose we only wanted a single element from the JSON data. To access a single element from a JSON array, pass the array index filter to jq , which follows the syntax .[x] with x representing an index value (positive and negative integer). To access the first element: To access the last element: To access the penultimate (second to last) element: To access the element at index 3 : If the index value is outside of the JSON array's bounds, then no element is returned by the array index filter: Here, the dataset only contains 41 rows. Therefore, any index beyond 40 causes the filter to return no element. If an index value is omitted, then all of the elements are returned by the array index filter: Additionally, the .[] filter can be used on JSON objects to return all top-level values within the object. In case you are unsure whether the input data is not valid JSON, then append a ? to the empty square brackets to suppress errors. For example, if the input data is a stringified integer value... Without the ? , the error jq: error (at <stdin>:1): Cannot iterate over number (1) will be thrown. With the ? , this error is suppressed as if no error occurred. Suppose we only wanted a subset of the JSON data. To extract a sub-array from a JSON array, pass the array/string slice filter to jq , which follows the syntax .[x:y] with x and y representing starting (inclusive) and ending (exclusive) index values respectively (positive and negative integers). It behaves similar to JavaScript's .slice() method. To extract the first element only: To extract the last element only: To extract all elements but the first element (omit the first element): To extract all elements but the last element (omit the last element): To extract the elements at indices 3 - 5 : To retrieve the length of a JSON array, pipe the output of an identity filter to the built-in length function: This returns the total number of elements within the JSON array. For our example dataset, the total number of records returned by the NYC Open Data API is 41 . For a JSON object, the length function returns the total number of top-level keys within this object. To retrieve the length of each item of a JSON array, pipe the output of a .[] slice filter to the length function: This returns a list of each element's length. For our example dataset, each record contains four pieces of information: the year, the population of NYC for that year, the total number of gallons (in millions) of water consumed by NYC residents per day and the average number of gallons of water consumed by a NYC resident per day. If an element is a string, then length returns the string's length. If an element is a null value, then length returns zero. To retrieve the top-level keys from JSON, use the built-in keys function. These keys are returned as an array of strings. Unlike the length function, the keys function requires no filter piping. By default, these keys are sorted alphabetically. Alternatively, the keys_unsorted function does not sort keys alphabetically and returns the keys in their original order. For JSON arrays, this function returns a list of indices. Experiment with these techniques on other JSON data sources/files.

    Thumbnail Image of Tutorial Processing JSON with jq

    I got a job offer, thanks in a big part to your teaching. They sent a test as part of the interview process, and this was a huge help to implement my own Node server.

    This has been a really good investment!

    Advance your career with newline Pro.

    Only $30 per month for unlimited access to over 60+ books, guides and courses!

    Learn More

    Visualizing Geographic SQL Data on Google Maps

    Analytics dashboards display different data visualizations to represent and convey data in ways that allow users to quickly digest and analyze information. Most multivariate datasets consumed by dashboards include a spatial field/s, such as an observation's set of coordinates (latitude and longitude). Plotting this data on a map visualization contextualizes the data within a real-world setting and sheds light on spatial patterns that would otherwise be hidden in the data. Particularly, seeing the distribution of your data across an area connects it to geographical features and area-specific data (i.e., neighborhood/community demographics) available from open data portals. The earliest example of this is the 1854 cholera visualization by John Snow , who marked cholera cases on a map of London's Soho and uncovered the source of the cholera outbreak by noticing a cluster of cases around a water pump. This discovery helped to correctly identify cholera as a waterborne disease and not as an airbourne disease. Ultimately, it changed how we think about disease transmission and the impact our surroundings and environment have on our health. If your data consists of spatial field/s, then you too can apply the simple technique of plotting markers on a map to extrapolate valuable insight from your own data. Map visualizations are eye-catching and take on many forms: heatmaps, choropleth maps, flow maps, spider maps, etc. Although colorful and aesthetically pleasing, these visualizations provide intuitive controls for users to navigate through their data with little effort. To create a map visualization, many popular libraries (e.g., Google Maps API and deck.gl ) support drawing shapes, adding markers and overlaying geospatial visualization layers on top of a set of base map tiles. Each layer generates a pre-defined visualization based on a collection of data. It associates each data point with certain attributes (color, size, etc.) and renders them on to a map. By pairing a map visualization library with React.js, developers can build dynamic map visualizations and embed them into an analytics dashboard. If the visualizations' data comes from a PostgreSQL database, then we can make use of PostGIS geospatial functions to help answer interesting questions related to spatial relationships, such as which data points lie within a 1 km. radius of a specific set of coordinates. Below, I'm going to show you how to visualize geographic data queried from a PostgreSQL database on Google Maps. This tutorial will involve React.js and the @react-google-maps/api library, which contains React.js bindings and hooks to the Google Maps API, to create a map visualization that shows the location of data points. To get started, clone the following two repositories: The first repository contains a Create React App with TypeScript client-side application that displays a query builder for composing and sending queries and a table for presenting the fetched data. The second repository contains a multi-container Docker application that consists of an Express.js API, a PostgreSQL database and pgAdmin. The Express.js API connects to the PostgreSQL database, which contains a single table named cp_squirrels seeded with 2018 Central Park Squirrel Census data from the NYC Open Data portal. Each record in this dataset represents a sighting of an eastern gray squirrel in New York City's Central Park in the year 2018. When a request is sent to the API endpoint POST /api/records , the API processes the query attached as the body of the request and constructs a SQL statement from it. The pg client executes the SQL statement against the PostgreSQL database, and the API sends back the result in the response. Once it receives this response, the client renders the data to the table. To run the client-side application, execute the following commands within the root of the project's directory: Inside of your browser, visit this application at http://localhost:3000/ . Before running the server-side application, add a .env.development file with the following environment variables within the root of the project's directory: ( .env.development ) To run the server-side application, execute the following commands within the root of the project's directory: Currently, the client-side application only displays the data within a table. For it to display the data within a map visualization, we will need to install several NPM packages: The Google Maps API requires an API key, which tracks your map usage. It provides a free quota of Google Map queries, but once you exceed the quota, you will be billed for the excessive usage. Without a valid API key, Google Maps fails to load: The process of generating an API key involves a good number of steps, but it should be straight-forward. First, navigate to your Google Cloud dashboard and create a new project. Let's name the project "react-google-maps-sql-viz." Once the project is created, select this project as the current project in the notifications pop-up. This reloads the dashboard with this project now selected as the current project. Now click on the "+ Enable APIs and Services" button. Within the API library page, click on the "Maps JavaScript API" option. Enable the Maps JavaScript API. Once enabled, the dashboard redirects you to the metrics page of the Maps JavaScript API. Click the "Credentials" option in the left sidebar. Within the "Credentials" page, click the "Credentials in APIs & Services" link. Because this is a new project, there should be zero credentials listed. Click the "+ Create Credentials" button, and within the pop-up dropdown, click the "API key" option. This will generate an API key with default settings. Copy the API key to your clipboard and close the modal. Click on the pencil icon to rename the API key and restrict it to our client-side application. Rename API key to "Google Maps API Key - Development." This key will be reserved for local development and usage metrics recorded during local development will be tied to this single key. Under the "Application Restrictions" section, select the "HTTP referrers (web sites)" option. Below, the "Website restrictions" section appears. Click the "Add an Item" button and enter the referrer " http://localhost:3000/* " as a new item. This ensures our API key can only be used by applications running on http://localhost:3000/ . This key will be invalid for other applications. Finally, under the "API Restrictions" -> "Restrict Key" section, select the "Maps JavaScript API" option in the <select /> element for this key to only allow access to the Google Maps API. All other APIs are off limits. After you finish making these changes, press the "Save" button. Note: Press the "Regenerate Key" button if the API key is compromised or accidentally leaked in a public repository, etc. The dashboard redirects you back to the "API & Services" page, which now displays the updated API key information. Also, don't forget to enable billing! Otherwise, the map tiles fail to load: When you create a billing account and link the project to the billing account, you must provide a valid credit/debit card. When running the client-side application in different environments, each environment supplies a different set of environment variables to the application. For example, if you decide to deploy this client-side application live to production, then you would provide a different API key than the one used for local development. The API key used for local development comes with its own set of restrictions, such as only being valid for applications running on http://localhost:3000/ , and collects metrics specific to local development. For local development, let's create a .env file at the root of the client-side application's project directory. For environment variables to be accessible by Create React App, they must be prefixed with REACT_APP . Therefore, let's name the API key's environment variable REACT_APP_GOOGLE_MAPS_API_KEY , and set it to the API key copied to the clipboard. Let's start off by adding a map to our client-side application. First, import the following components and hooks from the @react-google-maps/api library: ( src/App.tsx ) Let's destructure out the API key's environment variable from process.env : ( src/App.tsx ) Establish where the map will center. Because our dataset focuses on squirrels within New York City's Central Park, let's center the map at Central Park. We will be adding a marker labeled "Central Park" at this location. ( src/App.tsx ) Within the <App /> functional component, let's declare a state variable that will hold an instance of our map in-memory. For now, it will be unused. ( src/App.tsx ) Call the useJsApiLoader hook with the API key and an ID that's set as an attribute of the Google Maps API <script /> tag. Once the API has loaded, isLoaded will be set to true , and we can then render the <GoogleMap /> component. ( src/App.tsx ) Currently, TypeScript doesn't know what the type of our environment variable is. TypeScript expects the googleMapsApiKey option to be set to a string, but it has no idea if the REACT_APP_GOOGLE_MAPS_API_KEY environment variable is a string or not. Under the NodeJS namespace, define the type of this environment variable as a string within the ProcessEnv interface. ( src/react-app-env.d.ts ) Beneath the table, render the map. Only render the map once the Google Maps API has finished loading. Pass the following props to the <GoogleMap /> component: Here, we set the center of the map to Central Park and set the zoom level to 14. Within the map, add a marker at Central Park, which will physically mark the center of the map. ( src/App.tsx ) The onLoad function will set the map instance in state while the onUnmount function will wipe the map instance from state. ( src/App.tsx ) Altogether, here's how your src/App.tsx should look after making the above modifications. ( src/App.tsx ) Within your browser, visit the application at http://localhost:3000/ . When the application loads, a map is rendered below the empty table. At the center of this map is marker, and when you hover over this marker, the mouseover text shown will be "Central Park." Suppose we send a query requesting for all squirrel observations that involved a squirrel with gray colored fur. When we display these observations as rows within a table, answering questions like "Which section of Central Park had the most observations of squirrels with gray colored fur?" becomes difficult. However, if we populate the map with markers of these observations, then answering this question becomes easy because we will be able to see where the markers are located and identify clusters of markers. First, let's import the <InfoWindow /> component from the @react-google-maps/api library. Each <Marker /> component will have an InfoWindow, which displays content in a pop-up window (in this case, it acts as a marker's tooltip), and it will only be shown only when the user clicks on a marker. ( src/App.tsx ) Since each observation ("record") will be rendered as a marker within the map, let's add a Record interface that defines the shape of the data representing these observations mapped to <Marker /> components. ( src/App.tsx ) We only want one InfoWindow to be opened at any given time. Therefore, we will need a state variable to store an ID of the currently opened InfoWindow. ( src/App.tsx ) Map each observation to a <Marker /> component. Each <Marker /> component has a corresponding <InfoWindow /> component. When a marker is clicked on by the user, the marker's corresponding InfoWindow appears with information about the color of the squirrel's fur for that single observation. Since every observation has a unique ID, only one InfoWindow will be shown at any given time. ( src/App.tsx ) Altogether, here's how your src/App.tsx should look after making the above modifications. ( src/App.tsx ) Within the query builder, add a new rule by clicking the "+Rule" button. Set this rule's field to "Primary Fur Color" and enter "Gray" into the value editor. Keep the operator as the default "=" sign. When this query is sent to the Express.js API's POST /api/records endpoint, it produces the condition primary_fur_color = 'Gray' for the SQL statement's WHERE clause and will fetch all of the observations involving squirrels with gray-colored fur. Press the "Send Query" button. Due to the high number of records returned by the API in the response, the browser may freeze temporarily to render all the rows in the table and markers in the map. Once the browser finishes rendering these items, notice how there are many markers on the map and no discernable spatial patterns in the observations. Yike! For large datasets, rendering a marker for each individual observation causes massive performance issues. To avoid these issues, let's make several adjustments: Define a limit on the number of rows that can be added to the table. ( src/App.tsx ) Add a state variable to track the number of rows displayed in the table. Initialize it to five rows. ( src/App.tsx ) Anytime new data is fetched from the API as a result of a new query, reset the number of rows displayed in the table back to five rows. ( src/App.tsx ) Using the slice method, we can limit the number of rows displayed in the table. It is increased by five each time the user clicks the "Load 5 More Records" button. This button disappears once all of the rows are displayed. ( src/App.tsx ) To render a heatmap layer, import the <HeatmapLayer /> component and tell the Google Maps API to load the visualization library . For the libraries option to be set to LIBRARIES , TypeScript must be reassured that LIBRARIES will only contain specific library names. Therefore, import the Libraries type from @react-google-maps/api/dist/utils/make-load-script-url and annotate LIBRARIES with this type. ( src/App.tsx ) ( src/App.tsx ) ( src/App.tsx ) ( src/App.tsx ) Pass a list of the observations' coordinate points to the <HeatmapLayer /> component's data prop. ( src/App.tsx ) Altogether, here's how your src/App.tsx should look after making the above modifications. ( src/App.tsx ) Save the changes and re-enter the same query into the query builder. Now the table displays information only the first five observations of the fetched data, and the heatmap visualization clearly distinguishes the areas with no observations and the areas with many observations. Click here for the final version of this project. Click here for the final version of this project styled with Tailwind CSS . Try visualizing the data with other Google Maps layers.

    Thumbnail Image of Tutorial Visualizing Geographic SQL Data on Google Maps

      React Hooks - useCallback vs. useMemo

      As React functional components grow larger in size and involve more complexity, re-renders become less efficient and may adversely impact the application's performance. The worst the application's performance, the greater the likelihood of users being frustrated with slow and unresponsive pages. If you choose to ignore this declining performance, then users may forever leave your application for alternatives that offer better performance. React provides two built-in hooks for memoizing expensive computations: useCallback and useMemo . Learning the differences between the two hooks and knowing when to use them ensures that you understand the trade-offs associated with these hooks and don't prematurely optimize your application. Below, I'm going to show you... With memoization , we avoid re-calculating values by caching previously calculated values. For example, given a simple double function that calculates the product of an input number and two: Suppose we call the double function five times with the same argument 10 ... Each function call performs the exact same multiplication calculation of 10 * 2 and yields the exact same value of 20 . Calculating the product between two numbers can be considered a simple operation that requires little time to output a result, so caching would not be suitable in this case. However, for functions with long execution times, such as retrieving a list of suggestions based on user input (typeahead) via an API endpoint, caching could lead to significant performance gains. For example, if the user visits YouTube looking for videos related to JavaScript and types "JavaScript" into a search typeahead, then the typeahead will display suggestions for the inputted query "JavaScript." If the user decides to narrow down the search to videos related to JavaScript closures and adds "Closures," then the typeahead will display suggestions for the newly inputted query "JavaScript Closures." What if the user changes their mind again and wants videos only related to JavaScript? If the user deletes "Closures" within the typeahead, then the typeahead will once again display suggestions for the inputted query "JavaScript." If we cached the suggestions retrieved from the first time the user entered "JavaScript," then we avoid repeating an API call that would return results previously fetched. To memoize a function, define a function memoize that... Each time a function is memoized, a new cache is created for that particular function. In the above example, instead of calculating the product of 10 and 2 five separate times, the product is calculated only once, on the first function call. The benefits of memoization are more apparent for functions that require more time to finish execution. Memoization comes with the trade-off of saving execution time in exchange for greater memory consumption . Also, the above implementation of the memoize function works best with a pure function , which always evaluates the same result when given the same argument/s (deterministic) and causes zero side-effects. For an impure function , whether you should memoize it or not depends on its implementation. For example, with the typeahead example, because suggestions don't change frequently and users don't necessarily need the most recently updated suggestions with few to zero suggestions changed, the function for fetching these suggestions can be memoized. There are additional limitations to the above implementation of the memoize function, such as eventually running out of memory (and needing to implement a cache invalidation strategy) and memoizing based on multiple arguments rather than a single argument, but those topics are outside of the scope of this tutorial. To understand why the useCallback hook is important, let's walkthrough a simple example with a component that renders a list of numbers. Anytime an "Add Item" button is clicked, a new number is added to the list. ( src/App.jsx ) ( src/components/List.jsx ) Initially, the list starts with only one number, zero. If you press the "Add Item" button, then the number one is added to the end of the list. The number added to the list by the "Add Item" button is one more than the last number in the list. If you press the "Add Item" button again, then the number two is added to the end of the list. Each time a number is added to the list, the numbers state variable is updated with a newly concatenated number, and React re-renders the components affected by this update along with those components' children: the <App /> component (where the state change occurred) and the <List /> component (where a prop changed as a result of the state change). Anytime it re-renders a component, React recreates the functions defined within the body of the functional component as brand-new function objects. To track whether the component recreates the functions defined within it during subsequent re-renders: ( src/components/List.jsx ) If we restart the example application and open the developer tools, then you will notice only one function is within the set. If you press the "Add Item" button, then another function is added to the set. This means the <List /> component recreates the handleOnClick function anytime React re-renders it even though nothing about handleOnClick has changed. If we wrap the handleOnClick function with the useCallback hook, then the <List /> component only creates one instance of this function and memoizes it. Upon subsequent re-renders, the <List /> component does not recreate this function since it is already memoized. ( src/components/List.jsx ) Now, if you press the "Add Item" button multiple times, only one function will be stored within the set. The useCallback hook accepts two arguments: Currently, in the above example, the dependency array is empty. Therefore, this function remains the same across all subsequent re-renders. If we add items as a dependency, then each time we press the "Add Item" button, a new function is stored within the set. For each re-render, useCallback returns a different function instance. ( src/components/List.jsx ) In practice, dependencies should be specified only if the function references the dependency during execution. Suppose we adjust the <List /> component's handleOnClick function to print the value of a prop randomNumber instead of evt.target.innerHTML , like so: ( src/components/List.jsx ) Because this function relies on the value of this prop during execution, it should be recreated whenever this prop changes. Therefore, randomNumber is added to the dependency array. This component receives this randomNumber prop from the parent <App /> component. Within this component, let's add another button to set a randomNumber state variable when clicked. randomNumber is set to a random number generated by Math.random . ( src/App.jsx ) Restart the application. If we click the "Add Item" button, then the number of handleOnClick functions stored within the set functionStore remains one regardless of how many times we click this button. However, if we click the "Generate Number" button, then the randomNumber state variable within the <App /> component is updated to a new value and causes a re-render, which causes the <List /> component's handleOnClick function to be recreated since the randomNumber prop, a dependency, has changed. Now the set has two functions stored within it. Try out the above useCallback hook example in the CodeSandbox below: Note : If you see two functions being added to the set during any single re-render, then disable React Strict Mode from the root ReactDOM.render method since it runs certain callbacks/methods twice in the development environment. Let's quickly recap the purpose of the useCallback hook. This hook accepts an inline callback and a dependencies array. It memoizes the callback and returns the memoized callback. Whenever a dependency changes, React recreates the callback, memoizes this newly created callback with useCallback , which returns the newly memoized function. The useMemo hook accepts a "create" function and a dependencies array. The "create" function must return a value. useMemo memoizes the value returned by this function and returns the memoized value. Whenever a dependency changes, useMemo executes the "create" function to recompute the value, memoizes this value and returns the newly memoized value. If a dependencies array is not provided, then the value is recomputed on each re-render. This hook proves valuable for avoiding unnecessary expensive calculations involving large datasets. Suppose a component renders a large list of items and receives an items prop that is an array of items responsible for rendering the list of items. If the items of this items prop need to be normalized or transformed prior to rendering the list of items, then rendering the large list of items will be slow due to having to perform this extra step. Let's take our previous useCallback example and make several adjustments to the <List /> component to illustrate this scenario. ( src/components/List.jsx ) Here, the <List /> component transforms the items prop by converting each item to an object that preserves the original item's value and contains an additional field that holds a random number generated via Math.random . Then, it renders these new items. If we click the "Generate Number" button, then notice that the value of the random field changes: Clicking the "Generate Number" button changes the value of the randomNumber prop, which causes the <List /> component to recompute transformedItems despite this computation not involving this prop whatsoever. To avoid recomputing transformedItems whenever the randomNumber prop changes and only recomputing it when the items prop changes, memoize it with the useMemo hook: ( src/components/List.jsx ) Now, whenever we click the "Generate Number" button, the value of the random field remains unchanged. If we click the "Add Item" button, then the <List /> component receives the updated items prop and recomputes transformedItems since the items dependency has changed. Try out the above useMemo hook example in the CodeSandbox below: Try using the useMemo and useCallback hooks in your React applications. Remember to profile your application to identify its actual performance bottlenecks before using these hooks!

      Thumbnail Image of Tutorial React Hooks - useCallback vs. useMemo