Free Resources
Learning Unit Testing in Vue
Recommended Articles
Vue 3 Composition API - watch and watchEffect
Vue 3 Composition API - watch and watchEffect Introduction One of the major benefits to the new Composition API in Vue 3 is how it provides a flexible and powerful reactivity system to developers. With Vue 2, developers were reliant on the Options API to build single-file components, which enforced a level of structure to how the system was used. The Composition API, on the other hand, gives the developer new opportunities to build reactive applications. In a previous article, we explored the difference between ref and reactive methods. Let's build on that understanding, and introduce two new methods from the Composition API - watch and watchEffect. Options API - watch in the Options API The Options API provided us with the watch option, which is a way to observe when values changed and perform side effects based on that. Here's a basic example of what a watcher could look like with the Options API: ` Let's summarize what's going on here: In our template, we have a textarea that is bound to our data value of notes. In our Javascript, we have a watch key, which takes an object. In that object, we have a function, also called notes. This function will be automatically called whenever the value of notes changes (for example, when text is entered into the field). Each watcher takes two arguments: the new value, and the previous value. Since it's a function, we can do any validation or checks that need to happen here, and perform any side effects. In our example, when the text in the notes field changes, we are saving the value to a backend. For further reading on watchers with the Options API, here's a link to the documentation for Vue 2. Now that we have a basic understanding of watchers in the Options API, let's dive into the Composition API! watch and watchEffect The Composition API provides us with two different methods to handle side effects - watch and watchEffect. Just like with ref and reactive, these methods are not meant to compete with each other, but to be used as required by the application. Think of them as two similar tools that are each useful in certain cases. Both of these methods do the following: - Watch for changes in reactive variables - Allow the developer to perform side effects - Provide a way to cancel a side effect (in case the state has become invalid) However, there are a number of differences between them as well. Here's a short list of what makes them different: - watch can be used to lazily trigger side effects (watchEffect is always immediate). - watchEffect automatically watches for changes to any state changes (watch must be provided with a variable or variables to watch). - watch provides access to the current and previous values. It's important to take into account what you want to achieve, and use the correct tool for the job. As we work through this article, we'll do some comparison against the two options. Composition API - watchEffect Let's start refactoring the example above using watchEffect. Below is the same application using the Composition API: ` Since we are using the Composition API, we use ref to instantiate the notes variable. Also, we need to use notes.value, since it is a reference to the value and not the value itself. Finally, we return an object with notes so that it is available in the template. With watchEffect, we provide an anonymous function as an argument, then perform our side effect of saving the text. Note that we don't need to provide notes as a value to be watched - watchEffect is capable of watching any reactive variables that are referenced within the callback function. To highlight this, let's add a new variable to the mix - notesArePublic. Below is our updated application using two variables inside of the watchEffect: ` Now, whenever either notes or notesArePublic change, the side effect will be triggered and our save function will be called. This can cut down on a lot of code compared to the Options API, where you would need to create multiple watchers that do the same thing. A feature of the Composition API is the ability to remove watchers programmatically. Let's say that our user is done editing their notes, and wants to stop submitting values to the database. Both watch and watchEffect return a function that can be called to stop watching for changes. Let's update our code to include a button that turns off our watcher. ` When we call watchEffect, we are now saving its return as a variable, stopSaving. When the user clicks our Finish editing button, a function is called that will disable the watcher. Nice! This can be useful when your application is watching for a certain critera to be met. Once the state is how you are watching it to be, you can stop watching, preventing your side effects from being triggered when they shouldn't be. This can help your code stay organized, and clearly communicates to other developers that a watcher is only neccessary for a certain task. Another great feature is the ability to invalidate our side effects. In our example, what if the user enters more text after the save function has been called? By using the built-in invalidation, we can be aware when something has changed in our state and cancel our API request. Let's take a look at what that would look like. ` The callback function we passed into watchEffect now has an argument - onInvalidate. This function also takes a callback as an argument, which is called when the watched state has changed. In our example, the save function is now returning a function that we are calling cancel, which can be used to abort the API request. When onInvalidate triggers, we call cancel, aborting the API request. No need to wait for the response when it's already out of date! One thing to keep in mind is that watchEffect is immediately firing when your app loads. From the documentation, "To apply and automatically re-apply a side effect based on reactive state, we can use the watchEffect method. It runs a function immediately while reactively tracking its dependencies and re-runs it whenever the dependencies are changed." This means that immediately upon loading the page, our side effect is being triggered and data is sent to our API. This is very important to keep in mind! You may not want certain side effects (like saving an empty text field) to happen. If you need to lazily trigger effects, use the watch method instead. Another important note: watchEffect is not watching your variables deeply. If we had a single object of data, which contained both of our variables, those variables updating would not trigger the side effect. In this case, we could convert the reactive object to refs, which would then correctly trigger our side effect. ` Composition API - watch Now let's explore the watch method. We can improve it by adding some feedback to the user when their notes have been saved. To do this, we will add a new variable: showNotesSavedNotification, but we'll only show it for a specific amount of time. ` Using the watch method is very similar to how we would use functions with the watch option in the Options API. In fact, according to the documentation, "The watch API is the exact equivalent of the component watch property." In our example above, whenever content is saved, the showNotesSavedNotification variable is set to true. Our watcher is then called, setting a timeout and clearing the notification after five seconds. Let's go back to the point I made before about watchEffect being immediate. We don't really want to save an empty text field to our database - it's much more reasonable to wait for the user to enter a value first. Let's try using watch instead of watchEffect and see what benefits we get from it. ` We have removed watchEffect and replaced it with watch. Did you notice that the first argument to the method is an array with both of our values? We can use this syntax to watch multiple variables, rather than being tied to a single one. In this way, we still only have to write a single watcher, which is excellent for avoiding code duplication. Also of note - because we are watching an array, the values of value and oldValue are also arrays. For example, on the first keypress, oldValue would look like [ "", false ]. Depending on your use case, this might not be particularly helpful, but it's important to be aware of if you need to track the previous values of your watched variables. In addition, the watch method is still providing us with the ability to remove the watcher, as well as the onInvalidate method. This is another improvement over the Options API. Regardless of whether we use watchEffect or watch, we still get the benefits of the improved API. Let's make one last change to our application. I'd really like to bundle our notes and public status into a reactive object. Does that work with watch better than it did with watchEffect? Let's find out. ` Yes, in fact, we can watch our reactive object! According to the documentation, "A watcher data source can either be a getter function that returns a value, or directly a ref". In this case, since we are using a reactive object, we can pass in a function that returns our data reactive object, and the watcher will trigger as expected. Be aware that we technically could watch the data object directly, but this can have unintended consequences. Again from the docs, "Watching a reactive object or array will always return a reference to the current value of that object for both the current and previous value of the state. To fully watch deeply nested objects and arrays, a deep copy of values may be required." In this case, if we were to do this: ` Then both value and oldValue would be identical! This is clearly not what we meant to do. To avoid this, we are using the Spread syntax to create a new object which is both updating and being watched correctly, as well as not be passed by reference into both the current and previous values. One more point to be aware of: because the watch method is the same as what is provided in the Options API, we also have access to its options, like deep and immediate. So if you need to watch an object deeply, or trigger side effects immediately, you can still do so with the watch method! Conclusion Both watch and watchEffect have their uses. Both of them can be used to trigger side effects in your application. Next time you find yourself needing to trigger an effect in your code, ask yourself: - Does this effect need to be immediate? - Should it only trigger from a single source, or whenever its dependencies change? - Am I watching an object, or a ref? And of course, make sure that a side effect is really the correct course of action for your use case. Side effects can often be used when either a computed property, or a method is a better choice for the situation. Here's a link to an example of the final version of this code on Stackblitz. One last thing - because the Composition API doesn't need to be used within Vue single-file components, there are a lot of great uses for both watch and watchEffect. Here's a great presentation from VueConf Toronto where Oscar Spencer uses the Vue Composition API with an Express app to trigger side effects on Twitter. Check it out! Until next time!...
Apr 29, 2021
8 mins
Awesome 3D experience with VueJS and TresJS: a beginner's guide
Awesome 3D experience with VueJS and TresJS: a beginner's guide Vue.js developers are renowned for raving about the ease, flexibility, and speed of development their framework offers. Tres.js builds on this love for Vue by becoming the missing piece for seamless 3D integration. As a Vue layer for Three.js, Tres.js allows you to leverage the power of Three.js, a popular 3D library, within the familiar and beloved world of Vue components. This means you can create stunning 3D graphics and animations directly within your Vue applications, all while maintaining the clean and efficient workflow you've come to expect. TresJS is a library specifically designed to make incorporating WebGL (the web's 3D graphics API) into your Vue.js projects a breeze. It boasts several key features that make 3D development with Vue a joy: - Declarative Approach: Build your 3D scenes like you would any other Vue component, leveraging the power and familiarity of Vue's syntax. This makes it intuitive and easy to reason about your 3D elements. - Powered by Vite: Experience blazing-fast development cycles with Vite's Hot Module Replacement (HMR) that keeps your scenes updated in real-time, even as your code changes. - Up-to-date Features: Tres.js stays on top of the latest Three.js releases, ensuring you have immediate access to the newest features and functionality. - Thriving Ecosystem: The Tres.js ecosystem offers many resources to enhance your development experience. This includes: - Cientos: A collection of pre-built components and helpers that extend the capabilities of Tres.js, allowing you to focus on building your scene's functionality rather than reinventing the wheel (https://cientos.tresjs.org/). - TresLeches: A powerful state management solution specifically designed for 3D applications built with Tres.js (https://tresleches.tresjs.org/). You can try TresJS online using their official Playground or on their StackBlitz starter. But now, let's dive into a quick code example to showcase the simplicity of creating a 3D scene with TresJS. Setup First, install the package: npm install @tresjs/core three And then, if you are using Typescript, be sure to install the types: npm install @types/three -D If you are using Vite, now you need to modify your vite.config.ts file in this way to make the template compiler work with the custom renderer: ` Create our Scene Imagine a 3D scene as a virtual stage. To bring this stage to life, we need a few key players working together: 1. Scene: Think of this as the container that holds everything in your 3D world. It acts as the canvas where all the objects, lights, and the camera reside, defining the overall environment. 2. Renderer: This is the magician behind the curtain, responsible for taking all the elements in your scene and translating them into what you see on the screen. It performs the complex calculations needed to transform your 3D scene into 2D pixels displayed on your browser. 3. Camera: Like a real camera, this virtual camera defines the perspective from which you view your scene. You can position and adjust the camera to zoom in, zoom out, or explore different angles within your 3D world. - To make our camera dynamic and allow canvas exploration, we are going to leverage the client's OrbitControls component. Below are our examples. You will see that we just include the component in our canvas, and it just works. 4. Objects: These actors bring your scene to life. They can be anything from simple geometric shapes like spheres and cubes to complex models like characters or buildings. You create the visual elements that tell your story by manipulating and animating these objects. Starting from the beginning: to create our Scene with TresJS we just need to use our component TresCanvas in our Vue component's template: ` The TresCanvas component is going to do some setup work behind the scenes: - It creates a WebGLRenderer that automatically updates every frame. - It sets the render loop to be called on every frame based on the browser refresh rate. Using the window-size property, we force the canvas to take the width and height of our full window. So with TresCanvas component we have created our Renderer and our Scene. Let's move to the Camera: ` We just have to add the TresPerspectiveCamera component to our scene. NOTE: It's important that all scene-related components live between the TresCanvas component. Now, only the main actor is missing, let's add some styles and our object inside the scene. Our Vue component will now look like: ` And our scene will be: A Mesh is a basic scene object in three.js, and it's used to hold the geometry and the material needed to represent a shape in 3D space. As we can see, we can achieve the same with TresJS using the TresMesh component, and between the default slots, we are just passing our object (a Box in our example). One interesting thing to notice is that we don't need to import anything. That's because TresJS automatically generates a Vue Component based on the three objects you want to use in PascalCase with a Tres prefix. Now, if we want to add some color to our object the Three.js Material class comes to help us. We need to add: ` Conclusion Tres.js not only supercharges Vue.js applications with stunning 3D graphics, but it also integrates seamlessly with Nuxt.js, enabling you to harness the performance benefits of server-side rendering (SSR) for your 3D creations. This opens the door to building exceptional web experiences that are both interactive and performant. With Tres.js, Vue.js developers can leverage a declarative approach, cutting-edge features, and a vast ecosystem to bring their immersive web visions to life. If you want to elevate your Vue.js projects with a new dimension, Tres.js is an excellent choice to explore....
Jun 12, 2024
3 mins