Svelte Lifecycle Method - afterUpdate

In Svelte, a component's afterUpdate lifecycle method is called after the component is updated as a result of a state change. When the value of any of a component's props and variables changes, the component's beforeUpdate lifecycle method is executed prior to any DOM updates being made in response to these changes. Once the beforeUpdate lifecycle method is finished running, the DOM is updated to reflect the data changes. After completing this update, the afterUpdate lifecycle method is executed. Being able to schedule a callback to run at this phase of a component's lifecycle ensures that the DOM is completely updated and synced with any new state and prop values.

Here's a template of how the afterUpdate lifecycle method is used inside of a component:

When using the afterUpdate lifecycle method, remember that it runs on every state and prop change. For components that experience many state and prop changes, it can be quite cumbersome to track which variables/props have changed in order to then execute the appropriate code. This is unlike React's componentDidUpdate lifecycle method, which provides the previous props and state as arguments.

Below, I'm going to show you:

  • The versatility of hooking into the post-DOM update lifecycle phase.

  • Four demos that demonstrate practical use cases for afterUpdate.

Use Case #1 - Markdown Editor#

The Markdown syntax formats plain text into structured content that can be published to the web as valid HTML markup. Commonly, developers write API documentation and blog posts using Markdown. To avoid typos and inconsistencies while writing Markdown, tools and editors have been built to instantly live preview the rendered output of Markdown content.

Visit this simple Svelte REPL demo to see how to live preview Markdown using the markdown-it Markdown parser library and the afterUpdate lifecycle method:

Demo - afterUpdate Lifecycle Method - Markdown Editor

Demo - `afterUpdate` Lifecycle Method - Markdown Editor

Here, we have a <textarea /> element on the left for writing Markdown and a <div /> container element on the right for rendering the output of the Markdown. markdown-it provides a render method that accepts Markdown as an argument and returns the generated HTML as a string. This HTML string can be rendered as HTML using the @html template syntax.

Anytime an HTML string is rendered via the @html template syntax, the HTML string should be sanitized (before rendering) to prevent cross-site scripting, especially if the original source is untrusted. Pass the result of md.render as an argument to the sanitizeHtml function of the sanitize-html library to remove malicious HTML code.

Changes to the value of markdown (bound to the <textarea /> element via the bind:value directive) will trigger the afterUpdate lifecycle method, which will take this value and convert it to stringified HTML that is sanitized. This result will be rendered as HTML. As you type Markdown into the <textarea />, the output of the Markdown will be displayed and live updated, giving you immediate feedback on your Markdown.

Demo - `afterUpdate` Lifecycle Method - Markdown Editor - Some Markdown Added

Note: Alternatively, this same behavior can be achieved by using a reactive statement.

Use Case #2 - Theme Toggle#

Many websites provide a theme toggle to dynamically change their appearance based on a user's color preferences. To implement theming, use CSS variables and change the value of those variables whenever a different theme is selected.

Visit this simple Svelte REPL demo to see how to toggle themes using the afterUpdate lifecycle method:

Demo - afterUpdate Lifecycle Method - Theme Toggle

Demo - `afterUpdate` Lifecycle Method - Theme Toggle

Using a <div /> element with a class body to serve as a pseudo <body /> element, it has a background-color CSS property set to var(--background-color) and a color CSS property set to var(--color).

  • Clicking on the "Dark" button sets the CSS variables --background-color and --color to "#000000" and "#FFFFFF" respectively.

  • Clicking on the "Light" button sets the CSS variables --background-color and --color to "#FFFFFF" and "#000000" respectively.

These theme values are pre-defined in an object themes, and whenever any of these two buttons are clicked, the toggle function is called, and the theme variable is set to either themes.dark or themes.light (depending on the button clicked).

When theme is updated, the afterUpdate lifecycle method is called, and the values of the CSS variables are updated accordingly.

Demo - `afterUpdate` Lifecycle Method - Theme Toggle - Toggled to Dark

Note: Without label in the theme object, the afterUpdate lifecycle method would not be called because the theme object would not referenced anywhere in the HTML markup of the component.Note: Alternatively, this same behavior can be achieved by using a reactive statement.

Use Case #3 - Auto-Adjust Scroll Position in Messaging Client#

From top to bottom, chat clients display messages in ascending order of their timestamp, with the oldest messages at the top and the most recent messages at the bottom adjacent to the "Send Message" input field. When a new message is received within a chat client, the user is automatically scrolled to that message at the bottom of the scrollable view, assuming that they haven't scrolled beyond a certain threshold that indicates the user browsing through older messages.

Visit this simple Svelte REPL demo to see how chat clients auto-adjust a user's scroll position upon receiving a new message using the afterUpdate lifecycle method:

Demo - afterUpdate Lifecycle Method - Auto-Adjust Scroll Position in Messaging Client

Demo - `afterUpdate` Lifecycle Method - Auto-Adjust Scroll Position in Messaging Client

(ChatClient.svelte)

In this demo, there are two chat clients, one for a user named "Jesse" and another for a user named "Alex." Whenever any one of these two users sends a message, the message will be displayed in both clients since these messages are based on a conversation between these two users. Messages sent by the user are styled with a blue background and white text, while messages received by the user are styled with a light-grey background and black text. The <ChatClient /> retrieves these messages from a store:

When the user submits a new message, the addMessage method will be called to concatenate a new message to the messages array, and the input field where the user types messages will be cleared.

Because the messages array is modified (and is used to render messages), the beforeUpdate and afterUpdate lifecycle methods are called. beforeUpdate is called to determine whether or not to automatically scroll the user to the bottom of the <div /> container element (reference stored in messagesContainer) to see the new message. If the user is within 20px of the bottom-most scroll position of this container element, then the shouldAutoScroll flag will be set to true, and the client will automatically scroll to the bottom of this container element so that the user can see the latest received message. This must be done before the DOM is updated with the new message because adding a new message will increase the scrollHeight by more than the 20px threshold (due a message's minimum height), and thus, cause the calculation to keep assuming that you are browsing through older messages even though you are not.

Once the DOM is updated with the new message, the afterUpdate lifecycle method will be called, and it will scroll to the bottom of the container depending on the value of the shouldAutoScroll flag.

Use Case #4: Custom Svelte Action - Shuffle Animation#

To animate an element, the element must sequentially transition from a starting state to an ending state. For example, you may want to move a square from the top-left corner (starting state) of a view to the bottom-right corner (ending state) of a view. In between these two states, there may be intermediate states that the element must fulfill. For example, maybe you want the square to move in a zig-zag motion towards the bottom-right corner rather than in a straight diagonal motion. Additionally, parameters such as duration, timing function and delay must be factored into each step.

Referring back to the square example, each step in the animation requires knowing the most recent (x, y) coordinates of the square's position and the (x, y) coordinates of the square's next position in the zig-zag motion. And this continues on for each adjacent pair of steps in the animation sequence. At each step, you would cache the current coordinates of the square and calculate the difference between these coordinates and the next coordinates of the square.

Using the calculated displacement (and other parameters like the ones mentioned previously), the square can be animated from point A to point B.

In Svelte, animating an element can be done using the beforeUpdate and afterUpdate lifecycle methods. The below snippet of code is based on a demo presented at Svelte Summit 2020:

In the beforeUpdate lifecycle method, before each DOM update, the current coordinates (x and y) of the animating element (node) are cached. In the afterUpdate lifecycle method, after each DOM update, the cached coordinates are subtracted from the current coordinates to determine how far away these coordinates are from one another (dx and dy). Then, either a spring-based (via createSpringAnimation) or keyframe (via createKeyframes) animation is performed (via node.animate) using these calculated differences (keyframeFn({ dx, dy })).

Visit this Svelte REPL demo to see this in action:

Demo - afterUpdate Lifecycle Method - Custom Svelte Action - Shuffle Animation

Note: This demo is based on the Svelte Summit 2020 demo.

Demo - `afterUpdate` Lifecycle Method - Custom Svelte Action - Shuffle Animation

In this demo, pressing the "Shuffle" button randomly rearranges the cat pictures in a two column masonry grid layout (columns are 300px in width). The pictures are smoothly translated from one slot to another.

Each picture <div /> element is attached element-level lifecycle methods via a Svelte action (translate.action, prefixed with the use directive).

These methods are called when the element is created, destroyed, etc.

Here, translate.action is assigned the translateElement function, which contains the exact same code as previously mentioned with the beforeUpdate and afterUpdate lifecycle methods.

(translate.js)

If you continuously press the "Shuffle" button, then the pictures will be shuffled around until the "Shuffle" button is no longer pressed, at which point, the pictures will be able to animate to their designated new slots. This "shuffling around" behavior is made possible by the following code that uses the afterUpdate lifecycle method.

The tick function is called ensure that all pending state changes have been reflected to the DOM. Then, translate.flush executes all of the animation steps queued via the syncLayout.read and syncLayout.write methods in the translateElement function. This allows the translation animation to be ran smoothly irregardless of interruptions.

If this block of code was commented out, then the pictures would "blink" immediately to their designated new slots.

Note: Alternatively, you can use one of Svelte's built-in animation directives such as flip.

Next Steps#

If you have built React applications, then you will have probably noticed how similar afterUpdate is to componentDidUpdate/useEffect. Try rewriting some of the those components that use componentDidUpdate/useEffect as Svelte components that use afterUpdate.

If you want to learn more about Svelte, then check out Fullstack Svelte:

Sources#