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

useState - A Primer

Function components have come a long way since React v0.14. Introduced as a simpler syntax for defining stateless, presentational components, function components can now handle state via the useState Hook. This means you can define any component, stateful or stateless, with functions, and you no longer have to deal with the extra, unnecessary code that comes with classes. In fact, if you choose to write all your components as function components, then the bundle size of your React application significantly decreases. To understand how the useState Hook lets you manage state in function components, we must first revisit class components. When you create a class component, all of the component's state is stored within a single object. Within a class constructor, this object gets assigned to the component's state instance property, like so: To update a single value (or multiple values) of the component's state, call the component's setState() method: Try it out in a CodeSandbox demo here . With the useState Hook, you no longer have to define stateful components with the class syntax. Here's how you define the <App /> class component as a function component: Try it out in a CodeSandbox demo here . Notice how much smaller the component's definition has become. Anytime you write a class component, you end up repeating the same boilerplate code: The useState Hook is a special function that lets you add state to function components. When called, this Hook returns a state variable and a function for updating the state variable's value. The state variable contains the current state. The useState Hook accepts only one argument: the initial state. initialValueOfStateVariable can be anything: a string, a number, an object, etc. Conventionally, you unpack the state variable and update function from the array returned by the useState Hook. Additionally, you name the update function after the state variable, but prefixed with the word set . For a state variable named isMessageShown , its corresponding update function should be named setIsMessageShown . The update function behaves similarly to the setState method: However, there is a key difference between the two. While the setState method shallowly merges the component's new state with its old (most recent) state, the update function completely replaces the old state with the new state. For example, given an initial state of... Calling... Leaves user and count intact, but only changes the value of isMessageShown . The current state becomes a new object that contains the modified isMessageShown and the original user and count : Try it out in a CodeSandbox demo here . Note : For state with deeply nested objects, you may want to use the spread operator to preserve the nested values. On the other hand, the update function completely wipes out user and count and only keeps the modified isMessageShown in the new state: Try it out in a CodeSandbox demo here . As a best practice, you should... To learn more about the useState Hook, check out the second tutorial in the six-part YouTube series on React Hooks by Paige Niedringhaus, a Blues Wireless Staff Software Engineer and author of The newline Guide to Modernizing an Enterprise React App.

Thumbnail Image of Tutorial useState - A Primer

    Paige Niedringhaus Teaches You React Hooks In All New 6 Part Series

    We have a special 6-part YouTube tutorial series to share with you today that demystifies React Hooks and shows you how to build your apps with them. Hooks are so key to understand because, conceptually, React components have always been closer to functions. This will be the first of 6 lessons in this series, so follow along with the series to learn React Hooks from start to finish. Paige is a Staff Software Engineer at Blues Wireless and the teacher of newline's course: The newline Guide to Modernizing an Enterprise React App . Before her current work, she spent 5 years as a software engineer at The Home Depot, which gave her a thorough understanding of software development at scale, in large organizations. These are some of the same insights you will learn over the course of this 6-part series on React Hooks , including: In addition to the above, we'll also go into Custom Hooks and how to write your own, increasing the range of functionality you can implement using Hooks in your apps. We hope this series opens up your understanding of React Hooks and turns you into a virtual Hooks expert. Get started with the first tutorial in the series here .

    Thumbnail Image of Tutorial Paige Niedringhaus Teaches You React Hooks In All New 6 Part Series

    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

    Testing a Custom React Hook (useMap)

    Developers of the most popular React Hooks libraries rely on tests to enforce the overall quality of their libraries' code. Tests cover a wide variety of different use cases, give developers confidence that everything works as intended and serve as a form of documentation. Anytime a test fails, developers know which set of arguments to use to replicate the bug encountered and squash it lands in the distribution package. When writing a custom React Hook for a library, the Hook should be tested regularly and against the fringest of edge cases to appeal to a greater number of projects. Setting up a testing environment that executes tests fast and reliably requires the proper tools: This testing environment allows you to write tests that closely resemble your user's actions. For example, @testing-library/react comes with methods for rendering a React component ( render ) to a container ( document.body by default) and finding an element within the rendered content of this container via the element's label ( screen.getByLabelText ): With just these two methods, our test mimics, at a high-level, the browser rendering a contact form to the screen and the user searching for an e-mail address input field. In the case of React Hooks, you may not want to create dummy components for the sole purpose of testing your Hooks. A unit test for a React Hook should only test the Hook's functionality (independent of any component calling it). We should reserve the testing of Hooks called within a component for integration tests. Fortunately, the @testing-library/react-hooks library gives us testing utilities for testing Hooks in isolation without having to render any dummy components. Below, I'm going to show you how to test a custom React Hook built for a React Hooks library with the @testing-library/react-hooks library and Jest. To get started, clone this React Hooks library template from GitHub: This template has ESLint, TypeScript and Jest already configured and comes with a custom React Hook, useMap , which we will write tests for. Additionally, the @testing-library/react-hooks library has already been installed as a dev. dependency. The useMap Hook wraps around a Map object and mimics its API. If you would like to learn how to implement this Hook from scratch, then check out the blog post here . Within the __tests__ directory, create a new file, useMap.test.ts . We will write unit tests for the useMap Hook within this file. Within this file, import two methods from the @testing-library/react-hooks library: Then, import the useMap Hook. ( __tests__/useMap.test.ts ) Add a describe block with the text "useMap" to group all tests related to the useMap Hook within this one describe block. ( __tests__/useMap.test.ts ) Alongside the map state variable, which represents the Hook's current Map object, the useMap Hook provides several action methods for updating this state variable: From this point on, all describe blocks and tests will be written within the useMap describe block. Let's write a describe block for the set action method that covers two cases involving this action method: ( __tests__/useMap.test.ts ) For the "should update an existing key-value pair," we should render the useMap Hook using the renderHook utility method from the @testing-library/react-hooks library: ( __tests__/useMap.test.ts ) Here, we call the Hook with an array of one key-value pair. We pass this to a new Map object to create the initial map . The renderHook method returns an object with a result field. This field is a React ref. By reading the ref's current field, you can access the Hook's API (an array that contains the map state variable and the action methods). For now, let's omit the map state variable. I will explain why later on. ( __tests__/useMap.test.ts ) Let's double-check that our initial state was set correctly to a Map object with the key-value pair 1: "default" . ( __tests__/useMap.test.ts ) Save the changes. In the terminal, run the test npm script to verify that the initial state is set correctly: Now, let's call the set action to update the key-value pair of 1: default to 1: changed . We need to call the set action within the act method to flush any changes to the state into the simulated DOM before running any subsequent assertions. ( __tests__/useMap.test.ts ) Check that the key-value pair has been updated. The 1 key should have a corresponding value of "changed" . ( __tests__/useMap.test.ts ) Once again, save the changes. Run the test npm script to verify that the state has correctly changed: ( __tests__/useMap.test.ts ) With these few steps, you can write tests for the remaining action methods: ( __tests__/useMap.test.ts ) Remember how we omitted the map state variable and only accessed it from result.current[0] ? This is because all action methods are immutable. Therefore, anytime we call any one of these action methods, the map state variable destructured from the initial result.current will reference the initial Map object it's set to, not the new Map object that set it to internally in the Hook. Essentially, after the action method call, result.current references a completely different Map object than the one referenced by the destructured map state variable. Let's add a new describe block labeled "hook optimizations." Inside of this describe block, write a test to confirm this behavior: ( __tests__/useMap.test.ts ) Finally, let's write a test to make sure our useCallback and useMemo optimizations maintain reference equality after state changes. The reference to the action methods should never change. ( __tests__/useMap.test.ts ) Run the tests one final time and watch them all pass! Altogether... ( __tests__/useMap.test.ts ) For a final version of this code, visit the GitHub repository here . Try testing your own custom React Hooks with the @testing-library/react-hooks library.

    Thumbnail Image of Tutorial Testing a Custom React Hook (useMap)

    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.

    Creating Autonomous Web Components in Storybook

    Ever since the introduction of open source libraries and frameworks like React and Vue , the most popular approach for building user interfaces has been the composition of small, reusable components to create larger, more complex components and views. An often glossed over alternative that follows a similar paradigm is Web Components . As a collection of browser standards maintained by the WHATWG and W3C, Web Components lets you develop custom components, and use them anywhere in your application like regular HTML elements, with native browser APIs. It consists of three primary specifications that are implemented by all major browsers. Together, these specifications make self-contained components, each one encapsulating its own set of functionalities and structure: Third-party libraries and frameworks are known to frequently release new versions and introduce breaking changes. However, the lengthy, rigorous process of reviewing and approving changes to official specifications by the WHATWG and W3C results in far less breaking changes, which means less wasted development time. Using Web Components, components can extend from native HTML elements to augment their capabilities (i.e. clicking a table cell pops open a tooltip) while also retaining their accessibility characteristics. Commonly, Web Components can be found in applications built with Lit (successor of the deprecated Polymer library) or AMP . If we have to share components across different Web Components-based applications, then we need to be sure that these components can work standalone regardless of their environment. By building them in isolation within a UI development sandbox like Storybook , we can design resilient components that behave deterministically and cover a greater variety of common and edge use cases without the influence of outside data or business logic. Storybook allows you to visually test your components. Additionally, it organizes your components in a single place and serves as documentation for them. Below, I'm going to show you how to create autonomous Web Components-based components in Storybook. To get started, clone this component library template from GitHub: This template has Rollup , ESLint and TypeScript automatically configured so that we can focus exclusively on building and designing the library's components. Within this new project, install Storybook via the Storybook CLI. When the installation prompts you to pick a Storybook project type, select the html option. For this project, we will write the components with plain HTML and JavaScript. No JSX. No syntax that requires a compilation step. Note : The web_components option is for projects running Lit. For this tutorial, we will be creating the custom elements from scratch with native browser APIs. Delete the stories directory to remove all example stories from the project. Create two new directories, src and src/components , to house the custom elements made with Web Components. To verify that Storybook has been properly installed and recognizes our library's components, let's create a simple <hello-world /> custom element. ( src/components/HelloWorld.ts ) Note : The names of custom elements must be kebab-cased and cannot be single words. A custom element named "helloworld" will not be registered since it is considered a single word, whereas "hello-world" will be registered since there is a dash between each word. Define a new story for this component in a new file: ( src/components/HelloWorld.stories.ts ) A story describes a state that is supported by a component. Depending on its state, a component renders accordingly and demonstrates how a state addresses a specific use case. Here, we define a story for the <HelloWorld /> component named "Default." It receives no arguments and simply demos the default use case of displaying the text "Hello World" within a <span /> tag. All stories rely on a template, which determines how a story is rendered based on the arguments passed to it. In this case, since there are no arguments involved, the template function just returns stringified markup of the custom element <hello-world /> being used. The bind() method lets us make a new copy of the template per story. This way, we can customize the template based on each story's unique set of arguments. If you look inside the .storybook/main.js file, you will notice that Storybook expects all files matching the glob patterns ../src/**/*.stories.mdx and ../src/**/*.stories.@(js|jsx|ts|tsx) to export ( export default ) a configuration object following the Component Story Format . With this open standard, the default export represents the component's metadata, and each named export represents a story. The only required property is component , which we set to the component itself. The optional title property is set to the name of the component displayed in the sidebar of the Storybook. Slashes in the title help to organize the stories into distinct groupings. Now, let's create a slightly more complex component. This component, an informational tooltip, can be attached to the end of a phrase or sentence, and its contents can be customized based on whatever further elaboration you wish to provide. Within the src/components directory, create a new file named InfoTooltip.ts . ( src/components/InfoTooltip.ts ) The HTML template contains a <slot /> element, which allows for dynamic content that can be injected in place of the <slot /> element. In the context of the Shadow DOM, slotted content is accessible through the Light DOM as long as mode is set to open . Find the slotted content by executing document.querySelector('[slot="content"]') . For example, to recreate the tooltip shown in the previous picture, we nest an element with the slot attribute (set to the name of the <slot /> element to replace, which in this case is content ) within the <info-tooltip /> custom element: Within the src/components directory, create another new file named InfoTooltip.stories.ts . Let's write three stories for this component: ( src/components/InfoTooltip.stories.ts ) The template accepts one argument: the text to display within the tooltip. For each story, we define the arguments needed to describe the use case it covers. When we load Storybook, notice how the tooltip fails to fit within the canvas when hovering over (or focusing) the trigger. Let's fix this by applying a global decorator that wraps all of our stories' templates in a <div /> element with top and left margining of 4rem . ( .storybook/preview.js ) Reload Storybook. Now the tooltip fits within the canvas! Install @storybook/addon-controls as a dev. dependency: Add the Controls addon to the list of registered addons: ( .storybook/main.js ) By integrating the Controls addon to the configuration object, we can freely modify the text argument within the Storybook UI and see the resulting render in the canvas. The properties on argTypes map to what Storybook displays as the argument name in the Controls panel. In this case, the text argument is given the control name text . To enforce the text type for the text control, set the type to text . Assigning a text type for a control yields a text field next to the control's name in the Controls panel. For a final version of this project, visit the GitHub repository here . If you started out with a component-based library/framework like React, Vue, Angular or Svelte, then try out Web Components. To supercharge Web Components with features like reactivity and directives, consider using Lit .

    Thumbnail Image of Tutorial Creating Autonomous Web Components in Storybook