Understanding Svelte tick() lifecycle
Asked Answered
G

4

12

I'm halfway through the Svelte docs and I have a hard time understanding the tick() lifecycle. Is there an alternative to it in React?

For example, what it actually does in this example from the tutorial?

<script>
import { tick }  from 'svelte';
let text = `Select some text and hit the tab key to toggle uppercase`;

async function handleKeydown(event) {
    if (event.which !== 9) return;

    event.preventDefault();

    const { selectionStart, selectionEnd, value } = this;
    const selection = value.slice(selectionStart, selectionEnd);

    const replacement = /[a-z]/.test(selection)
        ? selection.toUpperCase()
        : selection.toLowerCase();

    text = (
        value.slice(0, selectionStart) +
        replacement +
        value.slice(selectionEnd)
    );

    await tick();
    this.selectionStart = selectionStart;
    this.selectionEnd = selectionEnd;
}
</script>

<style>
    textarea {
        width: 100%;
        height: 200px;
    }
</style>

<textarea value={text} on:keydown={handleKeydown}></textarea>
Ghiselin answered 18/4, 2020 at 19:51 Comment(1)
Tan Li Hau's answer is pretty clear but if you want an easier understanding please watch this - youtu.be/qrPySk2Oz68Meadowsweet
B
30

When you update your (reactive) variables, it does not immediately reflect onto the DOM, the updates are batched together with other changes and updates in the next update cycle.

Much like react, if you do

this.setState({ foo: 123 });

this.state.foo // you don't expect to read 123
// because this.setState is asynchronous!

Let's take a look at 1 example, and see how we do it in react vs svelte

Say you have a growing text input, which as you type, should grow in height, to accommodate more text.

Here's how you'd probably do it in React:

function GrowingTextInput() {
   const ref = useRef();
   const [value, setValue] = useState('');
   const updateText = (newValue) => {
     setValue(newValue);
     // NOTE: you can't measure the text input immediately
     // and adjust the height
     // you do it in useEffect
   }

   useEffect(() => {
     calculateAndAdjustHeight(ref.current, value);
   }, [value]);

   return <textarea value={value} ref={ref} />
}

you use useEffect to do adjustment on the DOM elements, after the state updates have been applied to the DOM.

In svelte, this is how you'd do it:

<script>
  let ref;
  let value;
  const updateText = async (newValue) => {
     value = newValue;
     // NOTE: you can't measure the text input immediately
     // and adjust the height, you wait for the changes to be applied to the DOM
     await tick();
     calculateAndAdjustHeight(ref, value);
   }
</script>

<textarea bind:this={ref} {value} />

In Svelte, to wait for the state changes to be applied, you await the promise returned from tick().


I've tried to explain it in a YouTube video, if you prefer something more visual:

https://youtu.be/JjONMdhaCDs

Also, here's my take on what other use cases that you can use tick() for:

https://dev.to/tanhauhau/2-amazing-use-case-of-tick-in-svelte-that-you-must-know-8pa

Blather answered 6/5, 2021 at 1:5 Comment(1)
In the React example, is there a good reason you wouldn't just run calculateAndAdjustHeight(ref.current, newValue); inside the updateText function?Ie
D
10

stuff you write after tick in svelte is the same as writing that in The second parameter to setState(). the second argument of setState is an optional callback function that will be executed once setState is completed and the component is re-rendered.

// change the state
await tick() // wait til the state is actually changed
// do x
// do y

In React it would be :

this.setState(..., () => {
// do x
// do y
})
Denyse answered 27/4, 2020 at 16:48 Comment(0)
H
1

I don't think so. From what I can tell it appears to be a way to queue up a value or continue function logic for use in the the "next render cycle". React's model is to collect all state/prop changes from the current render cycle, compute the next rendered output, and commit the change, thus starting the next render cycle.

Closest you get with React is this.setState with class-based components, or the useState hook for functional components.

Happily answered 18/4, 2020 at 20:7 Comment(0)
T
1

this is tick func:

export function tick() {
    schedule_update();
    return resolved_promise;
}
  • schedule_update() handles scheduling updates in the component. When tick() is called, it triggers this update process in Svelte.

  • resolved_promise is used to indicate that the update has been scheduled and that subsequent code should wait for any pending updates to be applied.

tick() ensures that any subsequent code execution happens after the pending updates have been processed by Svelte.

Tuchun answered 23/11, 2023 at 14:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.