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

Testing a Go and chi RESTful API - Route Handlers (Part 1)

Testing plays a fundamental role in the development of quality software. Shipping and deploying software with undetected bugs and regressions opens up a can of terrible consequences such as losing the trust of end users or costing the business time and resources. In a large collaborative setting, having developers manually test each and every feature and user flow for bugs and regressions wastes valuable time that can be put towards improving other aspects of the software. As the codebase and team grows, this approach will not scale. By writing unit/integration/end-to-end tests, identifying and catching bugs and regressions throughout an entire codebase becomes a painless, automatable task that can easily be integrated into any continuous integration pipeline. Unlike most other languages, the Go programming language provides a built-in, standard library package for testing: testing . The testing package offers many utilities for automating the testing of Go source files. To write a test in Go, define a function with a name prefixed with Test (followed by a capitalized segment of text) and accepts an argument of struct type T , which contains methods for failing and skipping tests, running multiple tests in parallel, formatting test logs, etc. Example : This test checks whether the Sum function correctly calculates the sum of two integer numbers. If the sum does not match the expected value, then the test logs an error message and marks itself as having failed. Try it out in the Go Playground here . Below, I'm going to show you: Clone a copy of the Go and chi RESTful API from GitHub to your machine: This RESTful API specifies five endpoints for performing operations on posts: If you would like to learn how to build this RESTful API, then please visit this blog post . In the testless branch's version of the RESTful API, the posts.go file has been moved to a routes subdirectory, and the route handlers within this file have been refactored into a routes package to allow the testing of packages independent of the main package. Run the following command to install the project's dependencies: Note : If you run into installation issues, then verify that the version of Go running on your machine is v1.16 . To get started, let's create a posts_test.go file within the routes subdirectory. This file will contain tests for each of the route handlers within the posts.go file. Inside of posts.go , each endpoint is defined on the chi router via a corresponding routing method named as an HTTP method. To register the GET /posts endpoint on this router, call the .Get method with the route / (in main.go , this posts sub-router is attached to the main router along the /posts route). ( routes/posts.go ) rs.List ( rs refers to the PostsResource{} struct) is a route handler method defined on the PostsResource{} struct. It retrieves a list of posts from the JSONPlaceholder API: ( routes/posts.go ) Let's write a unit test , which tests a single unit of code (commonly a function), for the PostsResource{}.List route handler function. Start off with a simple failing test that will immediately fail and print the message "Not yet implemented." to the terminal: ( routes/posts_test.go ) To test all packages within the current working directory recursively... To test the route handler for GET /posts : Let's combine these code snippets together: ( routes/posts_test.go ) Run the test: Congrats! The route handler test passes! Notice how the TestGetPostsHandler takes approximately half a second to run due to the network request the PostsResource{}.List route handler sent to the JSONPlaceholder API. If the JSONPlaceholder API experiences heavy traffic or any server outages/downtime, then the network request may either take too long to send back a response or completely time out. Because our tests rely on the status of a third-party service, which we have no control over, our tests take much longer to finish running. Let's work on eliminating this unreliability factor from TestGetPostsHandler . PostsResource{}.List calls the GetPosts function, which sends this network request and pipes the response back into PostsResource{}.List if there was no network request error encountered. ( routes/posts.go ) Since the function responsible for sending the network request ( GetPosts ) is a package-scoped variable within the routes package, this function can be replaced with a mock function , which replaces the actual implementation of a function with one that simulates its behavior. Particularly, the network request will be simulated. As long as the mock function has the same function signature as the original function, calling the route handler in a test will remain the same. Inside of posts_test.go , add a mock function for GetPosts : ( posts_test.go ) This mock function creates some dummy data ( mockedPosts , which is a list containing one post), encodes this data as JSON via json.Marshal and returns a minimal HTTP response with a status code and body. These fields adhere to the http package's Response struct. At the top of the TestGetPostsHandler test, set the GetPosts package-scoped variable to this mock function and change the expectedTotal to 1 : Run the test: Wow! The mock allows our test to run much faster. Click here for a final version of the route handler unit test. Try writing tests for the other route handlers.

Thumbnail Image of Tutorial Testing a Go and chi RESTful API - Route Handlers (Part 1)

How to Write Your First Component Test in React + TypeScript App

In the previous post , we created a unit test for a function. In this post, we're going to create a unit test for a component using @testing-library/react . Since we're using Create React App the React Testing Library is already installed in our dependencies. If you don't have it, install the package using: We will create a Greetings component with the greetings text inside and a button for sending friendly waves 😊 Let's create and review a component first: This component takes a name and an onSendWaves function as props. The name will be rendered in the greetings text, and the callback function will be called whenever the button is pressed. The button can be hidden if the callback function is not provided. We need to test 3 things here: Let's start with the first one. For the first test, let's check if the greetings text is rendered correctly. Let's break the test code down a bit. In describe and it we explain the assumption we want to test as we did in the previous post . Then, we use the render method from the @testing-library/react package. This method renders the component provided in arguments and appends it to the body of the document. Once we're rendered the component we can use the screen object to get access to the render result. It provides a set of queries for us to find the required element. If you saw tests with RTL before, you might have seen this: We use getByText query to find an element that contains the given text. Notice that React Testing Library doesn't focus on the component implementation. We don't explicitly define where to look for that text, instead, we tell what to find and RTL will try to find it for us. Finally, we check that the required element is indeed in the document. We can select elements not only by the text they contain. In fact, there are quite a few ways to query elements . Let's review a couple of types of queries : Another cool (and a bit confusing at first) feature is the query type. Until now we only saw a getBy query. It searches for a single element and returns it if found and throws an error if didn't find. There are also other types of queries for different types of searches : The queryBy and queryAllBy are usually used to make sure that elements are not in the document. The findBy and findAllBy are used to search for elements that are not available at first render. It is hard to pick a query at first, that's why there is a priority guideline in the docs and the cheatsheet to help us. Now, let's test that when the onSendWaves is provided the button gets rendered: Here, we use getByRole query because we need to find a single button element. React Testing Library has the fireEvent object that can help with simulating browser events, however, it is more convenient to use the user-event library since it provides more advanced simulation of browser interactions. Let's install it with: Now let's test that when the button is pressed it fires the callback: First of all, we use jest.fn method to create a mock function . This mock will help us to test how many times and with what arguments this function has been called. On the last line, we check that the mock instance ( onSendWavesMock ) is called at least once with a given text. Another text will result in the failing test. To click the button we use the userEvent object from React Testing Library. It provides most common actions like click, input changes, and so on. In our case, we need to test the click action, so we use the click method and pass the element that should be pressed. In the next post, we will test react hooks with @testing-library/react-hook .

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

How is Svelte different than React?

To get a better understanding of what Svelte brings us, it helps to step back and look at how we got here: Back in the 90s, in the original version of the web, there was only HTML. Browsers displayed static documents without any interactivity. The only way to get updated information, was by reloading the page, or navigating to a new page. In 1995, Netscape released JavaScript , making it possible to execute code on the end-user's machine. Now we could do things like: As developers began experimenting with this newfangled JavaScript thing, they found one aspect really tough: dealing with the differences between browsers. Both Netscape Navigator and Internet Explorer did things in their own way, making developers' responsible for handling those inconsistencies. The result was code like: This kind of browser detection code littered codebases everywhere. The extra branching was a nuisance, like a cognitive tax, making code harder to read and maintain. Translation: not fun. In 2006, John Resig released a compatibility layer called jQuery . It was a way to interact with the DOM without being an expert on browser feature matrices. It completely solved the inconsistency issue. No more if (isNetscape) or if (isIE) conditions! Instead, we could interact with the page using CSS selectors, and jQuery dealt with the browser on our behalf. It looked like this: But there were some challenges here too: In 2010, Google launched AngularJS 1.x , a framework that helps with state management. Instead of writing jQuery code, like: Expressions (called bindings) could be embedded directly inside the HTML: and Angular would sync those bindings for us. Later, if we change our HTML, say by switching an <h1> to an <h2> , nothing breaks with the Angular version. There's no CSS selectors to update. AngularJS components looked like this: The magic was that anytime you changed something on the $scope variable, Angular would go thru a "digestion cycle", that recursively updated all the bindings. But there were some problems here too: In 2013, Facebook launched React , a library for syncing state with UI. It solved some issues that AngularJS 1.x had. It's isomorphic, it can render HTML both on the server and in the browser, fixing the SEO problem. It also implemented a more efficient syncing algorithm called Virtual DOM . Refresher: Virtual DOM keeps a copy of the DOM in memory. It uses the copy to figure out what changes (the delta), while limiting potentially slow interactions with the browser DOM. (Though it's been pointed out that this may be overhead .) It's still conceptually similar to AngularJS, from a state management perspective. React's setState({value}) or in more recently, the useState() hook, is roughly equivalent to Angular's $scope.value = value . Hook example: React relies on developers to signal when things change. That means writing lots of Hook code. But Hooks aren't trivial to write, they come with a bunch of rules , and those rules introduce a extra cognitive load into our codebases . In 2019, Rich Harris released Svelte3. The idea behind Svelte is: What if a compiler could determine when state changes? That could save developers a lot of time. It turns out to be a really good idea . Being a compiler, Svelte can find all the places where our code changes state, and update the UI for us. Say we assign a variable inside a Svelte component: Svelte detects the let statement and starts tracking the variable. If we change it later, say year = 2021 , Svelte sees the assignment = as a state change and updates all the places in the UI that depend on that binding. Svelte is writing all the Hooks code for us! If you think about it, a big part of a developer's job is organizing state, moving state back and forth between the UI and the model. It takes effort, and it's tricky to get right. By offloading some of that work to compile-time tools, we can save a lot of time and energy . Another side effect is, we end up with less code . That makes our programs smaller, clearer to read, easier to maintain , cheaper to build, and most importantly: more fun to work with. P.S. This post is part of a new course called "Svelte for React Devs" So stay tuned!

State Management with Svelte - Stores (Part 3)

Disclaimer - If you are unfamiliar with the Context API in Svelte applications, then please read this blog post before proceeding on. You must understand the limitations of the Context API to better understand stores and how they address those limitations. For components in a Svelte application to share data irregardless of the subtree they belong to in the component hierarchy, Svelte provides stores for handling global state via the svelte/store module. Unlike the Context API, which involved setting contexts directly in the <script /> block of a component via setContext , stores can be created outside of a component in their own dedicated modules. Yet, like the Context API, a store can only contain a single value. This value can be a primitive, an object, an array, etc. When a component subscribes to a store, the component can receive the updated value from the store and re-render accordingly. Like props, stores are reactive . Stores are designed to cover practical use cases such as theming, accommodating internalization/localization (i18n), persisting a logged-in user's information, etc. Svelte supports four types of stores: A readable store is a store whose value cannot be set within a component subscribed to it. Components can only read from it and cannot write to it. To create a readable store, first import the readable function from the svelte/store module: Then, call the readable function. It accepts two arguments: The readable function returns an object containing a subscribe method, which allows a component to subscribe to the store and listen for changes to its value. The subscribe method accepts a single argument, a function that provides the store's value. Commonly, a component variable is set to this value so that it can be displayed or used for the component's internal state. This method returns an unsubscribe method, which allows the component to unsubscribe from the store. The unsubscribe method is called within the onDestroy lifecycle method to avoid memory leaks, which can result from the component being instantiated and being destroyed many times, leaving subscriptions of previous component instances still in memory. Example #1 : A component subscribes to a readable store with the value "Hello World!" It sets the message variable to this value, and this message is rendered within the <h1 /> element. The UI will display "Hello World!" in big, bold text. ( Component.svelte ) Example #2 : <ComponentA /> and <ComponentB /> both subscribe to a readable store imported from an external module, stores.js . Whichever component first subscribes to the store will trigger the function passed as a second argument to the readable method, which will print "Only called once!" to the developer tools console and replace the default value of "Hello World!" with "Lorem Ipsum." When the other component subscribes to the store, the function passed as a second argument to the readable method will not be triggered. When these components subscribe to the store, their message variable will be set to the store's value, now "Lorem Ipsum," and this message is rendered within the <h1 /> element. The UI will display two "Lorem Ipsum" in big, bold text. ( stores.js ) ( ComponentA.svelte / ComponentB.svelte ) ( Parent.svelte ) A writable store is a store whose value can be set within a component subscribed to it via pre-defined methods. Components can read from and write to it. To create a writable store, first import the writable function from the svelte/store module: Then, call the writable function. It accepts the same two arguments as the readable function mentioned above: an initial value of the store and a function that provides a set function for setting the value of the store. The writable function returns an object containing three methods: Example #1 : A component subscribes to a writable store with the value zero. It sets the count variable to this value, and this count is rendered within the <h1 /> element. Initially, the UI will display 0 in big, bold text. Along with this text, the UI will present two buttons, one for incrementing the count by one each time it is clicked and one for resetting the count back to zero. To increment the count by one, use the store's update method, which accepts a function that provides the current value of the store as an argument and returns the new value to be set to the store. When the "Increment" button is clicked, the count rendered within the <h1 /> element will be updated to the newly incremented value. To reset the count to zero, use the store's set method, which accepts the value to be set to the store. Pass it the value zero. When the "Reset" button is clicked, the count rendered within the <h1 /> element will be updated to zero. ( Component.svelte ) Example #2 : <ComponentA /> and <ComponentB /> both subscribe to a writable store imported from an external module, stores.js . Whichever component first subscribes to the store will trigger the function passed as a second argument to the writable method, which will print "Only called once!" to the developer tools console and replace the default value of zero with one-hundred. When the other component subscribes to the store, the function passed as a second argument to the writable method will not be triggered. When these components subscribe to the store, their count variable will be set to the store's value, now one-hundred, and this count is rendered within the <h1 /> element. The UI will display two "100" in big, bold text along with two sets of "Increment" and "Reset" buttons. When any of the "Increment" buttons is clicked, the two count values rendered will be incremented by one (store values are reactive, and both components are subscribed to the same store). When any of the "Reset" buttons is clicked, the two count values rendered will be changed to "0." ( stores.js ) ( ComponentA.svelte / ComponentB.svelte ) ( Parent.svelte ) A derived store is a store whose value is derived from values from at least one store. Because the derived value depends on other stores, its value cannot be set by a component. Components can only read from it and cannot write to it. To create a derived store, first import the derived function from the svelte/store module: Then, call the derived function. It accepts three arguments: Like the readable function, the derived function returns an object containing a subscribe method, which allows a component to subscribe to the store and listen for changes to its value. Example : A component subscribes to both a writable store, which contains an RGB value (an array of three numbers, each representing an individual channel of an RGB value), and a derived store, which contains an HSL value derived from this writable store's RGB value. Both are set with default values representing the color white in their respective formats: [255, 255, 255] and [0, 0, 1] . The inputs under the "RGB" section of the UI are each bound to a value in the rgb array, which is set to the value of the RGB store ( rgbStore ). The inputs under the "HSL" section of the UI are each bound to a value in the hsl array, which is set to the value of the HSL store ( hslStore ). When the user changes the value of any one of the three inputs (restricted to numbers within the range 0 to 255) under the "RGB" section of the UI, the values of the three inputs under the "HSL" section of the UI will be changed to the HSL value equivalent to this RGB value. Svelte Derived Store Demo - RGB-HSL Conversion ( utils.js ) ( stores.js ) ( Component.svelte ) Thus far, subscribing to a store in a component involves a lot of boilerplate code: This boilerplate code grows proportionally to the number of stores the component subscribes to. For a component that is instantiated and destroyed many times, it is important to unsubscribe the component from the stores it subscribes to. Otherwise, the component's subscriptions remain in memory long after it's been destroyed, which will cause a memory leak . Fortunately, Svelte provides a convenient shortcut for components to auto-subscribe to stores. By prefixing the imported store's name with $ , the component automatically subscribes to the store and unsubscribes from the store when it is destroyed. Plus, the component can reference the store's value in its template without having to assign it to an extra variable and receive updates to this value. Let's rewrite the component in the derived store example using auto-subscriptions: To try it out, visit the demo here . ( stores.js ) ( Component.svelte ) Wow! Talk about a much cleaner approach! No longer will you need to manually subscribe to each store and write all of the unsubscription-related code involving the onDestroy lifecycle method. Under-the-hood, auto-subscriptions automatically handles all of this logic. With auto-subscriptions, you can name the store after the value it contains rather than just naming it as a store. In the above example, notice how the previously named rgbStore is now named rgb . This way, when its value is referenced in a component's template via the $ prefix, the name will reflect the value itself ( $rgb ). Also, an input can bind directly to the writable store's value and update it whenever the user changes the input's value. For writable stores, assignments done directly to these $ -prefixed variables will call the store's set method using the value to be assigned. This will set the rgb store's value to [0, 0, 0] upon the component's instantiation. Changing the rgb store's value will cause the derived value in the hsl store to be set to [0, 0, 0] . To retrieve the value of a store once (non-reactive), use the svelte/store module's get function. This is useful for allowing components to access values from stores they are not subscribed to, but yet, may need to access once in a while. Under-the-hood, get subscribes the component to the store, reads its value, and then, unsubscribes the component from the store all in one method. Let's take the refactored derived store example that uses auto-subscriptions, and rewrite the component to only convert the RGB value entered into the inputs to its HSL equivalent when the user clicks on a "Convert" button: To try it out, visit the demo here . ( Component.svelte ) Here, changes to the RGB inputs no longer automatically update the HSL inputs. When the user changes the value of any of the inputs in the RGB section, they must now click the "Convert" button, which retrieves the HSL value from the hsl store. The get method allows components to access such store values only when necessary. A custom store is an object that provides, at the minimum, the same functionality as any one of the native stores (readable or writable), and that can also provide additional functionality geared more towards domain-specific logic. When this object contains a "properly implemented" subscribe method, the object fulfills the store contract . This allows the object to be treated as a store. Its value becomes reactive, and the store can be referenced with the $ auto-subscription prefix. A "properly implemented" subscribe method must accept a function as an argument. This function must provide the store's value as an argument. Upon subscribe being called or the store's value being updated, this function will be called immediately (and synchronously), providing the store's current value as its argument. Additionally, this function must either... Referring back to the the svelte/store module's readable and writable methods, these methods provide minimal store implementations that fulfill the store contract: When a custom store optionally provides a set method, which sets the store's value and calls all of the store's active subscription functions, the store becomes a writable store. Let's take the refactored derived store example that uses auto-subscriptions, and modify the rgb store to provide additional methods for resetting the store's value to something pre-defined. In this case, setting the store's RGB value to red's, blue's, green's, black's or white's RGB value. To try it out, visit the demo here . ( stores.js ) If the custom store relies on readable or writable , then destructure out the methods they return ( subscribe , and for writable specifically, set and update ) and return them in the object representing the custom store. Group all of this code within an IIFE ( Immediately Invoked Function Expression ), which will contain all of the custom store's implementation details while not interfering with other custom stores that rely on readable or writable . The rgb custom store, previously a pure writable store, now provides five additional methods ( resetToBlack , resetToWhite , resetToRed , resetToGreen and resetToBlue ), each one setting this store's value to a pre-defined RGB value. ( Component.svelte ) Components can auto-subscribe to custom stores in the same way they can to pure readable, writable and derived stores. To access any of the custom store's methods, simply reference it via its corresponding property in its object representation. For example, rgb.resetToBlack references the resetToBlack method of the rgb store. If the user clicks on any one of the five buttons, then the value of the inputs under the RGB section will be changed to a pre-defined RGB value, and the inputs under the HSL section will also be changed due to them binding to a value of a derived store ( hsl ) that depends on the rgb custom store. Often, custom stores are useful for augmenting the capabilities of writable stores, such as validating a value prior to setting it as the store's value. Major e-commerce websites, such as Amazon, feature shopping cart buttons in their navigation bars. For a user to add a product to their shopping cart, they must first visit the product's detail page and press a button to add this product to their shopping cart. The shopping cart will be updated with the product. At any time, the user can remove the product from their shopping cart. Because components representing a product page and a navigation bar are likely to not have an ancestor-descendant relationship in a component hierarchy, to communicate with each other, they will both need to connect to a single store containing cart-related data. Svelte Store Demo - E-Commerce Shopping Cart ( App.svelte ) The demo displays a hypothetical e-commerce webpage. The <Header /> component serves as the navigation bar for this webpage, and it contains the shopping cart button. The <Products /> component shows all of the available products for the user to add to their cart and purchase later. ( stores.js ) This demo application involves four stores: ( Header.svelte ) The <Header /> component serves as a navigation bar. Here, it has a "Log In" link and a shopping cart button. ( Cart.svelte ) When the shopping cart button is clicked, a dropdown will appear. When the user adds a product to their cart, this dropdown will display this product, the sub-total of the entire cart, the amount to discount from the sub-total, an input for applying a coupon and a total (calculated as the difference of the sub-total and the discount). In this component, the auto-subscription $ prefix is used to directly access the cartStore 's and costStore 's values in the template code for rendering the cart's products, discounts and costs. Additionally, auto-subscriptions automatically handle store subscriptions and unsubscriptions. When a coupon is applied, it is checked against the list of valid coupons in $validCouponStore . If the coupon is found and recognized as a valid coupon, then it is added to the cartStore , which will then cause costStore to update the discount amount and total. A valid coupon can only be applied once. ( Products.svelte ) This component displays the products in the productStore . Notice how manually subscribing/unsubscribing to a store adds more boilerplate code to the <script /> block. When the user presses the "Add to Cart" button of a product, this will add the product to the cartStore via its addItem custom method. Svelte's built-in support for state management covers many common use cases, such as implementing site-wide theming, translating content for multiple locales (i18n) and handling the authenticated user's information. Recent versions of other front-end libraries, like Vue.js and React.js, have introduced their own built-in state management solutions. In Vue 2, provide / inject bindings are not reactive , which is similar to Svelte's Context API . In Vue 3, provide / inject can be used with the Composition API to add reactivity between provided and injected values via the ref / reactive method. Alternatively, a store pattern using the reactive method can be adopted for managing state. In pre-React v16, React offered an experimental Context API , and their documentation discouraged updating the context due to intermediate parent components possibly returning false in their shouldComponentUpdate lifecycle methods. In React v16+, React introduced an official Context API that is considered to be more efficient. Both of these versions of React's Context API are reactive. Using Vue 3's provide / inject Composition API and React v16+'s Context API, the data must come from a parent component and can only be shared with components within its subtree. In Vue 3, the parent component calls the provide method within its setup option to allow its child components to access those values when they call the inject method within their setup options. In React v16+, it is very common to see entire applications wrapped within global provider components so that the application state can be accessed by any component within the application's component hierarchy. With Svelte's stores, you don't have to wrap any components with a higher-order provider component or tie global state to a component. Just define a store within an external module and import it directly into any component whenever it is needed, irregardless of wherever the component is within the component hierarchy. Of course, there are third-party libraries such as a Redux that can also fulfill an application's state management requirements. Redux is a state management library for centralizing state in a single, immutable store (outside of components) and manipulating the state in this store predictably by dispatching pre-defined actions, which are each mapped to a different shape of the state in the store (based on the outcome of the manipulations). Over the recent years, criticism of Redux has grown as front-end libraries/frameworks implemented their own state management solutions. Often, the main complaint of Redux has been the " bloat " it adds to an application's production bundle. However, most developers seem to integrate Redux into their applications when they really don't need it. For the additional kBs Redux adds to a production bundle and the extra memory it consumes, Redux provides: If you don't need all of the boilerplate code and features that come with Redux, then you probably don't need Redux and can manage an application's state with the front-end technology's built-in state management solution. Remember to always evaluate the trade-offs! Try rewriting your Vue - Vuex or React - Redux (or Context API) projects with Svelte. You will likely be surprised at and appreciate the simplicity, flexibility and robustness of Svelte stores. If you want to learn more about Svelte, then check out Fullstack Svelte :

Thumbnail Image of Tutorial State Management with Svelte - Stores (Part 3)