Tutorials on React Library

Learn about React Library 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

Implementing a useMap React Hook

Ever since the introduction of Hooks into the React library, creating cleaner, reusable components has become much easier. Instead of using render props and higher-order components, Hooks provide us a way to share stateful logic across multiple components without making any modifications to an application's component hierarchy. React comes with several built-in Hooks for handling component state and lifecycle, such as useState and useEffect , that can be composed to create all kinds of different Hooks. Creating your own custom Hooks can be tricky. Once you decide upon the part of a component to extract out into a separate function as a custom Hook, you need to carefully refactor this stateful logic to... For example, a Hook that manages authentication should... Keeping the Hook simple, broad and flexible opens up the components that can use it. In this case, any component that depends on the user's authentication status, such as a navigation bar to determine whether or not to display a login button or a dropdown toggle, can call this Hook and have access to its state and methods, all with a single line. When done properly, you can even abstract your Hooks into a React Hooks library for other developers to use in their own applications (irrespective of business logic). Below, I'm going to show you how to implement a custom React hook, useMap , within a React Hooks library. The useMap Hook wraps around a Map object and mimics it's API. This allows your React components to leverage Map objects without having to worry about low-level details like try...catch error handling. To get started, clone this React Hooks library template from GitHub: This template has ESLint, TypeScript and Jest already configured so that we can write, lint, test and build the useMap Hook for distribution. Within the src directory, create a useMap.ts file, which will contain the source code of the useMap Hook. Unlike plain JavaScript objects, Map objects can set objects as keys. This is quite useful for situations like mapping DOM elements to a corresponding piece of data or functionality. Additionally, Map objects are iterable, and keys set on the Map object will not conflict with properties inherited from the Object prototype like toString and constructor . The useMap Hook's API will closely follow the original React Hooks API of returning a pair of values: the current state and action methods for updating it. The Hook will return a Map object as the state and the following action methods for interacting with this object: Each time we perform any of these actions on the Map object, we create a new instance of a Map object to make it immutable to change. Here's how a component would call this Hook: Note : In the above code, the Map object maps DOM elements to strings. Let's start by implementing the Hook's state and setValue action method: ( src/useMap.ts ) The Hook can be passed a Map object or an array of key-value pairs (entries) to initialize the keys and values of the map state variable. If nothing is passed to the Hook, then initialState is set to a new, empty Map object by default. Define the clear action method, which empties the Map object of its key-value pairs: ( src/useMap.ts ) Define the set action method, which adds a new key-value pair or replaces an existing key-value pair: ( src/useMap.ts ) Define the deleteByKey action method (publicly exposed as delete ), which deletes a key-value pair: ( src/useMap.ts ) Define the initialize action method, which initializes map to a new Map object based on a passed tuple (or other iterable object). ( src/useMap.ts ) If any of these action methods are passed to a child component via props, then anytime map changes and causes the calling parent component to re-render, this triggers a re-render of its child components even though none of these methods changed. To prevent this unnecessary re-render, we should wrap each action method with useCallback and memoize the actions object with useMemo , like so: ( src/useMap.ts ) Since the keys and values of the map state variable can be of any type, they should be generically typed . Let's denote the generics by the type variable <K, V> : K for a key and V for a value. This type variable preserves the type information of the key-value pairs. Let's make use of this type variable by defining a type MapOrEntries that describes... ( src/useMap.ts ) Rewrite the useMap function as a generic function and annotate the initialState and mapOrTuple parameters with this type, like so: ( src/useMap.ts ) Finally, we need to define a type for the array, consisting of the map state variable and the action methods, returned by the Hook. Name this type UseMap , and define it as the following: ( src/useMap.ts ) Now, define the UseMapActions type, which provides a type definition for each action method: ( src/useMap.ts ) The Dispatch type tells TypeScript that setValue is a function that returns nothing. This is perfectly valid because this method simply updates the map state variable. That's it. The SetStateAction type tells TypeScript that setValue can be passed either... Altogether... ( src/useMap.ts ) Don't forget to export the types and the Hook inside the src/index.ts file! ( src/index.ts ) For a final version of this Hook, visit the GitHub repository here . Try refactoring your custom React Hooks into a separate React Hooks library, and share them with other team members and/or developers.

Automating a React Library's Build Process with RollupJS and Babel

The meteoric adoption of TypeScript in recent years has led to the increased publication of well-documented, robust libraries. TypeScript boosts developer productivity and lessens the likelihood of bugs (and typos) by embracing static code analysis and feeding suggestions to code completion engines, but at the cost of additional bloat (from type annotations and syntactic sugar) and tooling requirements. Although TypeScript is a superset of JavaScript, web browsers and runtimes, such as Node.js, cannot execute TypeScript code. Furthermore, applications written in JavaScript cannot import TypeScript libraries as modules. If you choose to write a library in TypeScript, then you need to identify the library's target audience: Depending on the configuration of your library's build process, the library's module bundler can output compiled versions of the library that address these scenarios. For example, if a developer has written their application using the module format ES modules , then they can import the ES module version of the library (outputted into a .mjs file by the module bundler) at the top of the application's source code via an import statement. Since ES modules was released several years ago as part of the ES6 standard, the JavaScript language had no native implementation for importing/exporting modules prior to the ES6 standard. With older module formats, such as CommonJS and UMD, still actively used by some codebases, you may want to specify these formats as outputs of the library's module bundler to maximize the library's usage and adoption by other developers. Commonly, a library's build process involves the RollupJS module bundler and Babel JavaScript compiler convert code written with the latest features of JavaScript (and/or non-standard syntaxes, such as TypeScript and JSX) into efficient " flat distributables ." Babel compiles the code while RollupJS generates a distributable (within a dist folder) for each module format you decide to support. For example, the library may have one distributable for CommonJS (a .cjs file) and another for ES module (an .mjs file). Regardless of the module format, these distributables are capable of running on older JavaScript engines. Ideally, anytime you make changes to your library and push those changes to its remote repository, those changes should trigger an automated workflow to rebuild the distributables and bump its version accordingly. Updating distributables this way allows developers to quickly receive the latest copies of your library. Below, I'm going to show you how to automate a React library's build process using RollupJS and Babel. To get started, clone the following repository: This repository contains a component library with customizable D3 visualizations written in React and TypeScript. Currently, this repository only has one visualization component, a scatterplot. Inside of the project directory, install the dependencies: For this tutorial, we will be adding RollupJS and Babel to this library. Browsers and certain environments cannot run TypeScript and JSX code. Therefore, we must install Babel to compile this code into JavaScript code that can run on these technologies. Plus, you may need to transform newer JavaScript features (ES2015+), such as arrow functions or async / await , if you decide to target older browsers, such as Internet Explorer. Note : A plugin applies a single transformation to the code, whereas a preset is a collection of plugins. To configure Babel, create a .babelrc.json file. Inside of .babelrc.json , list the installed presets and plugins. For this library, let's target browsers with more than 0.2% market share and are not considered "dead." ( .babelrc.json ) Note : >0.2% , not dead and not op_mini all are queries used to filter for the target browsers. To check out the list of browsers that fall under these Browserslist queries, run the following command: Before installing RollupJS, the library must provide an entry point , which tells RollupJS where to start building the bundle. RollupJS crawls the library's modules to create a module dependency graph based on its imports/exports. From there, RollupJS uses this graph to drop any unused dependencies (known as tree-shaking) and generate the bundle using the finalized graph and an object of output options. The entry point serves as the root node of the graph and determines which modules will end up in the bundled output. For this library, the entry point is src/index.ts , which exports each React component (along with their prop interfaces) via aggregate exports. ( src/index.ts ) All components exported within this module are publicly available to be consumed by applications importing it. Install the following dependencies: Within the root of the project directory, create a rollup.config.js file, which configures RollupJS. Commonly, RollupJS configurations involve three options: ( rollup.config.js ) For our library, we will output two bundles: one for CommonJS and one for ES modules. Since the output option of the RollupJS configuration references file paths from package.json , let's update the package.json file with these paths, which tell RollupJS where to place the build output. ( package.json ) Note : sideEffects reassures a module bundler that unused modules do not have "side-effects," and thus, they can be safely removed from the module dependency graph. Essentially, this option grants the module bundler permission to tree-shake. Now, let's update package.json 's scripts with build scripts. ( package.json ) Finally, run the following command to build the library: Check out the contents of the dist/index.cjs.js and dist/index.esm.js files. Notice that in both files, all instances of let and const have been replaced with var , JSX code has been replaced with calls to React.createElement , etc. For a final version of this tutorial, check out the GitHub repository here . Add a build process to your React library!

Thumbnail Image of Tutorial Automating a React Library's Build Process with RollupJS and Babel

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