Tutorials on State Management

Learn about State Management 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

React Hooks 101 - Part 2: The useState Hook and State Management in Function Components

Here is the second tutorial in our 6 part YouTube series on React Hooks. We've already seen that React Hooks are arguably the biggest fundamental change to happen to React since its inception. Learning Hooks brings you up to speed with this important update to React. Now in this second tutorial, we will teach you the ins and outs of using the useState hook, the most commonly used React Hook, and thus, one of the most important ones you should know. You will see that state management using the useState hook is in many cases more straightforward than using class-based components. 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 verbose code that comes with classes. Using the useState hook, you can keep track of state changes as the user interacts with your functional components, much as you could do with class-based components. Your instructor for the tutorial is Paige Niedringhaus, who's a Staff Software Engineer at Blues Wireless, and an expert at React as well as related frontend technologies. Paige has a depth of experience in software development with large organizations, including at The Home Depot, where she spent 5 years in engineering. In this part 2/6 React Hooks tutorial, she covers: Mastering the contents of this free tutorial gets you ready to use the most commonly used React Hook and understand React code that uses it. Get started with the tutorial here. And watch for the continuation of the series, when we move into the other hooks you'll use most frequently on React projects. If you want to dive deeper into React and master the best practices for modernizing any React app, then check out Paige's full course: The newline Guide to Modernizing an Enterprise React App . This course covers it all: React Hooks, Design Systems, Testing, and best practices for modern React.

Thumbnail Image of Tutorial React Hooks 101 - Part 2: The useState Hook and State Management in Function Components

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

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

Building a GraphQL Application with Vue 3 and Apollo

RESTful APIs adhere to a reliable architectural standard for transferring data statelessly over the HTTP protocol. Every endpoint of an API semantically describes how a resource should be created ( POST ), read ( GET ), updated ( PUT / PATCH ), deleted ( DELETE ), etc. Large, data-driven applications consume data from multiple third-party/in-house sources, and each one exposes a unique set of endpoints to manage different resources. Adapting these applications to support a wide range of platforms and device sizes (commonly mobile, desktop and web) may present several problems: Using Facebook's GraphQL query language, the client specifies its exact data requirements to the server via a single endpoint. Establishing a schema (written with the syntax of the GraphQL Schema Definition Language) creates a contract between the client and server that defines what data can be read from and written to the data graph by the client. This data graph centralizes all of the APIs consumed by your application by mapping each field to a resolver that populates it with a value retrieved from an endpoint of one of these APIs, a database, etc. A client can fetch data from a GraphQL server via plain HTTP and then manually update the UI accordingly. However, GraphQL clients such as Apollo Client abstract away the low-level implementation details of these features underneath a declarative API. Built by the Apollo GraphQL team, Apollo Client is an open-source GraphQL client that provides a lot of out-of-the-box functionality for communicating with a GraphQL server: To integrate Apollo Client into an application using another JavaScript library/framework besides React, which Apollo Client already has built-in support for, there exists view integration libraries within the Apollo ecosystem that provide bindings for Vue , Svelte , Angular , Ember and Web Components . The Vue Apollo library integrates Apollo Client into a Vue application. Different versions of Vue Apollo are compatible with different versions of Vue: Although Vue Apollo v4 is still in active development (alpha phase), it offers support for Vue 3's Composition API , which collocates the methods corresponding to component options ( watch , computed , etc.) and lifecycle hook registrations ( onMounted , onUnmounted , etc.) within a single component option, setup . Using Vue Apollo v4 methods, such as useQuery and useMutation , the data requirements are also placed within the setup method. This approach makes it much easier to reason about a component's code compared to the Vue Apollo Options API approach, which places the data requirements within an apollo component option (independent of the other code placed within the remaining component options). Below, I'm going to show you: Using Vue 3's Composition API and the Vue Apollo (v4) library, we will be building the following GitHub search client: To start, download this project from GitHub: This repository is based on a custom Vue CLI project template that runs Vue 3 and includes support for TypeScript, ESLint and Prettier. If you want to learn how to manually set up the base structure of this project, then proceed to the next section (" Installation "). Otherwise, you may skip the " Installation " section, download the already prepared project structure and proceed directly to the " GitHub GraphQL API " section. To generate a new Vue CLI project, run the following command in the terminal: When prompted with "Please pick a preset," select the "Manually select features" option: This project will support TypeScript. Press "Space" to select "TypeScript." When prompted with "Choose a version of Vue.js that you want to start the project with," select the "3.x (Preview)" option: Vue components will not be written with the class syntax. The Class API was officially dropped . This project will use Babel alongside TypeScript. For linting and code formatting, select the "ESLint + Prettier" option: Anytime changes to a file are saved, run the linter. For this project, let's place the Babel, ESLint, etc. configurations within their own dedicated files to avoid increasing the size of package.json . These answers are only for this project. In the future, you may want to try out different sets of project configurations to determine what specific tools make you more productive. To integrate type definitions from the schema of GitHub's GraphQL API , install @octokit/graphql-schema : Several type definitions are assigned nullable types , which will cause ESLint to raise the following error within your IDE. Inside of the .eslintrc.js file, turn off the rule @typescript-eslint/no-non-null-assertion . ( .eslintrc.js ) In 2017, GitHub publicly released its GraphQL API . GitHub's GraphQL API exposes a public schema for interacting with GitHub itself, whether fetching commit data or starring a repository, all accessible from a single endpoint. To send requests to GitHub's GraphQL API, generate an access token. This access token must be set to each request's Authorization header. When setting permissions for the access token, enable repository privileges. Create a .env file at the root of the project directory. Copy the 40 character-long access token to your clipboard. Set the environment variable VUE_APP_GITHUB_ACCESS_TOKEN to this access token. ( .env ) Note : Environment variables prefixed with VUE_APP_ can be accessed via process.env within Vue applications. Without this prefix, environment variables are undefined . First, install graphql , @apollo/client and @vue/apollo-composable as dependencies: To rapidly style the UI interface, we will be using the Tailwind CSS framework. Install tailwindcss , postcss and autoprefixer as dependencies: Then, create a minimal Tailwind configuration file ( tailwind.config.js ) at the root of the project directory. Note : The -p flag creates a minimal PostCSS configuration file ( postcss.config.js ) at the root of the project directory, alongside the generated tailwind.config.js . Inside of tailwind.config.js , set the purge option to a list of filenames/globs for PurgeCSS to analyze and remove unused CSS. ( tailwind.config.js ) Inside of public/index.html , add these two CSS classes to the <body /> element: ( public/index.html ) When you run the application, you will encounter the following error: Although the latest version of the tailwindcss PostCSS plugin (v2) is compatible with latest version PostCSS (v8), other tools within the PostCSS ecosystem may not yet be compatible with this version of PostCSS. To resolve this error, uninstall tailwindcss , postcss and autoprefixer , and then reinstall these dependencies with the PostCSS (v7) compatibility build. Inside of main.ts (the entry point of the Vue 3 application), create an ApolloClient instance. Let's pass an object containing configuration options to the Apollo Client: For this application, we will define two links: To inject the Apollo Client into the application and allow child components to access the Apollo Client, call the provide method within the createApp 's setup method to "provide" this client to the application and its children components. Since this application only interacts with a single GraphQL API, set this client as the default client. Putting it altogether... ( main.ts ) Our application requires three child components: By default, the reactive searchOptions object, which represents the arguments passed to the GitHub GraphQL API's search query, is dynamically assigned to the prop search-options of the <RepositoryList /> component. Any changes to searchOptions , particularly to query , which corresponds to the value of the search bar's input, will cause the <RepositoryList /> component to retrieve a new list of repositories. The value of query is changed whenever the search event is emitted from the <SearchBar /> component, which occurs on changes to the value of its input. ( src/App.vue ) Typing a query emits a "search" event with the current query and triggers the search function in the <App /> component. This search function sets the value of the query field in the reactive searchOptions object. Debounce the handleInputChange event handler to avoid sending the search event on every single input change. ( src/components/SearchBar.vue ) When an event is fired, this debounce function starts a timer and waits for a specific time period to elapse before calling its corresponding event handler. If another event is fired during this time period, then the previous event is ignored. The timer resets and must wait for the specific time period (now reset) to elapse before calling the new event's corresponding event handler. This debounce function invokes the event handler on the trailing edge of the timeout. ( src/utils.ts ) Store the queries and mutations within a single file. This application requires only one query and two mutations: If you decide to add more queries/mutations that return a repository/repositories, and you request for the same repository fields for those queries/mutations, then use the repo fragment to keep your code DRY. ( src/graphql/documents.ts ) Inside of the <RepositoryList /> component, fetch a list of repositories based on the searchOptions passed from the <App /> parent component. To fetch this list of repositories, the component executes the composition function useQuery , which accepts a GraphQL document ( SEARCH_REPOS ) as the first argument and query arguments ( searchOptions ) as the second argument. This function is compatible with the setup function of Vue 3's Composition API. useQuery returns an object that contains several Ref values: Sometimes, a query may return multiple top-level objects. To pick a single object from the result object returned by useQuery , use the useResult composition function. Instead of referencing the repositories from the result object as result.search.edges in the component's template, it can just be referenced as repositories . Plus, the default value assigned to repositories is the second argument passed to useResult (in this case, an empty array). ( src/components/RepositoryList.vue ) Inside of the <Repository /> component, there is a button for starring/unstarring a repository, depending on whether or not you have starred the repository previously. If you have not yet starred the repository, then clicking the button will star the repository, and vice-versa. The event handler calls either the unstarRepo or starRepo functions to unstar or star a repository respectively. Each of these functions execute the composition function useMutation , which accepts a GraphQL document ( ADD_STAR or REMOVE_STAR ) as the first argument and options (an object containing mutation arguments via the variables property, etc.) as the second argument. Similar to useQuery , this function is compatible with the setup function of Vue 3's Composition API. When a repository is starred/unstarred, we must update the cache to reflect this mutation. To understand why this is important, let's walkthrough an example. Imagine you typed the query "facebook" into the search bar's input. This will fetch all repositories relevant to "facebook" from GitHub's GraphQL API. Suppose you have already starred the facebook/react repository, and you decide to unstar it. After you unstar it, you decide to type the query "google" into the search bar's input. This will fetch all repositories relevant to "google" from GitHub's GraphQL API. If you again type the query "facebook" into the search bar's input, then this will fetch all repositories relevant to "facebook" from the Apollo Client's cache . What was cached previously for this query was a list of repositories relevant to "facebook," including the facebook/react repository. However, this repository was cached when it was still starred. Therefore, we must modify this repository in the cache to reflect that it was recently unstarred. To update the cache, set the update property in the options object to a function that provides an instance of the cache and the data returned from a mutation. This function will call the overrideMutationStarCache , which will read the already cached data (via the cache 's readQuery method) and write the result of the mutation to the appropriate repository entity (via the cache 's writeQuery method). Don't forget to also increment/decrement the stargazers count! Putting it altogether... ( src/components/Repository.vue ) Run the application locally: Visit localhost:8080 in a browser to interact with the application. In this blog post, we only explored a very small subset of the GitHub GraphQL API. Try experimenting with other aspects of the public schema of the GitHub GraphQL API. For a more difficult challenge, try connecting an existing Vue 3 application to a custom GraphQL server. If you want to learn more about Vue 3, then check out Fullstack Vue :

Thumbnail Image of Tutorial Building a GraphQL Application with Vue 3 and Apollo

Getting Started with GraphQL in React using Apollo Client

Apollo is a great interface for fetching and managing data through GraphQL. When we’re building applications with GraphQL, it’s important to manage data effectively to have a smooth development experience. This is where Apollo steps in, and acts as an abstraction layer over GraphQL (which is just a query language) , and provides a robust platform for data fetching. The power of Apollo lies with how much we get out of the box (it’s a lot). We don’t need to do lengthy custom setups or configurations and can get started right away. Here, we’ll be discussing the benefits and usage of Apollo Client with ReactJS, but it’s important to note that most of the same features are also available in Angular and Vue. Before we dive deeper into Apollo, let’s briefly discuss GraphQL. GraphQL is a query language, built by developers at Facebook that emphasizes predictable results by building schemas for building queries. We use a tree structure to fetch data through a single central API endpoint. With traditional REST APIs, we are usually exposing multiple APIs for different purposes. For example, we might have an API to fetch books, and a different API to fetch authors. Similarly, we may have APIs to get a singular book or author. With GraphQL, we only hit a single endpoint, but we use fields to fetch only the data we need, such as only the name of the book, in a sea of different available parameters made available by the back-end. By making a single request, our application can be fast even on slow mobile networks. The type system of GraphQL keeps the API structure robust, and the dev tools help us see the schema definitions to easily debug our requests. Moreover, it solves the problem of over-fetching and under-fetching, as we’re able to get exactly the data we need in one hit. Its optimistic UI and caching make all interaction with the server super fast and snappy. On the server-side, we import the required libraries and create schemas for Queries and Mutations, respectively. This prevents us from spending time thinking of complex API flows. Queries are used to read data, whereas Mutations are used to create, update, or delete the data. Here is a very basic example from the GraphQL documentation: First, we build the schema where all our possible queries lie, Now, we can create a root resolver that hosts all our functions corresponding to the queries we have created: Finally, we can initialize our application with GraphQL. The algorithm itself is very simple, it resolves each field before diving inside and doing the same until all the fields are resolved. After that, the result is returned in the required format. To describe and initiate our queries on the front-end, we can use the graphql library to hook into our React components, this will give us our resultant data as props. More often, people choose to go with libraries such as Apollo and Relay. Here, we’ll be discussing how Apollo specifically provides us with a toolkit to make our lives easier when working with GraphQL. Firstly, we need to include the required functions from apollo-client, apollo-link-http and apollo-cache-inmemory. We can create a client instance through ApolloClient, where we’ll pass two things: Now, we can call our query function with the defined query. Here, we’re getting all books for authors that are aged less than or equal to 25. Note, we’re using the JavaScript template syntax to write our queries. If using the graphQL extension, it will also provide us with syntax highlighting. We can do much more with queries like this, for example, we may choose to hit a different resolver to get all the books of a specific author. As Apollo uses Context API under the hood, to enable it to access our components, we need to wrap our root element with ApolloProvider. Next, we need to define our query. It’s better to create a folder structure where all our queries and mutations are in specific folders so it’s easier to navigate during development. Here, we’ll create a userQueryBooksByAuthor.js file, where we’ll define and export our query. Now, we can import this in the file for our React component where we’ll be calling this query and use it with the hooks Apollo provides. useLazyQuery allows us to query programmatically on events. For example, we click a button to load the books, in that case, the click handler function will look something like this: And to call it: Here, we’re passing the authorName from our click function, but we could also have this come from anywhere, such as a state variable. If we wanted to run the query every time a component loads, we can call the useQuery hook instead, in this way: Now, all we need to do is conditionally render our data. We can simply do that in our return statement in this fashion: Mutating data with Apollo Hooks is just as easy. We can call the useMutation hook, pass in the required variables to update our data, and get our results back. First, we initialize our hook and create our useMutationUpdateAuthorName.js file in our mutations folder: And, Now, we can call it conditionally. Like before, we’ll call the mutation on a button click. And to call it: Typically, when we’re working with REST APIs, we need to have some sort of state management solution for our React apps. This is because we need to keep track of our data, loading states, and success/error responses. This can sometimes make our code harder to navigate. However, Apollo provides us with caching as well as variables that hold the loading and API call result states directly. This means we don’t need to create further state variables, as we can just fetch them out of the query or mutation that we run as seen in the previous example. Moreover, we don’t need to store the fetched data in state either. Since Apollo caches all the results, if we query for the same data again, it will avoid making unnecessary API calls and instead look into the memory first to find a cached version of the call. From experience, it's clear that GraphQL is being considered more day by day by developers against traditional REST servers. One common use-case I’ve encountered is fetching data from Content Management Systems, where a specific data model is defined. This makes it easy to think of our data in a tree structure and to fetch what we need based on conditions quickly and efficiently. There’s no doubt that it allows developers to think of a different approach when handling data management between clients and servers. And Apollo is right at the forefront, providing even more features and possibilities to make things convenient for developers.

Thumbnail Image of Tutorial Getting Started with GraphQL in React using Apollo Client