Categories
JavaScript React

Using React Strict Mode to Avoid Deprecated Code and Side Effects

React is a library for creating front end views. It has a big ecosystem of libraries that work with it. Also, we can use it to enhance existing apps.

In this article, we’ll look at how to use React’s strict mode to get extra warnings about deprecated APIs and side effects during development.

Strict Mode

Strict mode is a tool for highlighting potential problems in an application. It doesn’t render any visible UI.

It’s only used to activate additional checks and warnings for its descendants.

Strict mode doesn’t affect the production build.

We can add strict mode to a React app as follows:

class App extends React.Component {  
  render() {  
    return (  
      <div>  
        <p>foo</p>  
        <React.StrictMode>  
          <p>bar</p>  
        </React.StrictMode>  
      </div>  
    );  
  }  
}

In the code above, the p tag with ‘foo’ isn’t checked by strict mode since it’s outside of the React.StrictMode component, but the p element inside is checked by strict mode.

Identifying Unsafe Lifecycles

Strict mode checks for unsafe lifecycles. Some lifecycle methods are being deprecated because they encourage unsafe coding practices.

They are:

  • componentWillMount
  • componentWillReceiveProps
  • componentWillUpdate

The UNSAFE_ prefix will be added in an upcoming release.

2 new lifecycle methods are replacing the ones above. They’re the static getDerivedStateFromProps and getSnapshotBeforeUpdate methods.

getSnapshotBeforeUpdate lifecycle is called before mutations are made, and the return value of it will be passed as the 3rd parameter to componentDidUpdate .

getSnapshotBeforeUpdate and componentDidUpdate together covers all the user cases for componentWillUpdate .

Strict mode will warn about the deprecation of old lifecycle hooks.

Warning About Legacy String ref API Usage

Also, React strict mode will warn about using string refs in our code.

String refs are deprecated because they can’t be statically typed. They need to always be consistent. Magic dynamic strings break optimizations in VMs, and it only works on one level.

We can’t pass it around like callback and object refs.

Therefore, it’ll warn us about the usage of string refs since they’re deprecated.

Callback refs and createRef are both supported in the future.

Warning About Deprecated findDOMNode Usage

The findDOMNode method is deprecated. We can use it to search for a DOM node given a class instance.

We shouldn’t need to do this because we can attach a ref to a DOM node.

findDOMNode only returns the first child, but it’s possible for a component to render multiple DOM levels with the use of Fragments.

Therefore, it isn’t very useful now since it only searches one level and we can use ref to get the exact element we’re looking for.

We can attach a ref to the wrapper element instead:

class App extends React.Component {  
  constructor(props) {  
    super(props);  
    this.wrapper = React.createRef();  
  }  
  render() {  
    return <div ref={this.wrapper}>{this.props.children}</div>;  
  }  
}

If we don’t want to wrapper div to be rendered, we can set display: contents in our CSS if we don’t want the node to be part of the layout.

Detecting Unexpected Side Effects

React works in 2 phases:

  • The render phase makes any changes to the DOM. React calls render during this phase and then compares the result to the previous render.
  • The commit phase runs any lifecycle methods to apply any changes required.

Render phase lifecycles include the following class component methods:

  • constructor
  • componentWillMount
  • componentWillReceiveProps
  • componentWillUpdate
  • getDerivedStateFromProps
  • shouldComponentUpdate
  • render
  • setState

Since they may be called more than once, they shouldn’t commit any side effects. Ignoring this rule may lead to problems like memory leaks and invalid app state.

Strict mode checks if side effects are made by running the following methods twice:

  • Class component constructor method
  • The render method
  • setState
  • The static getDerivedStateFromProps lifecycle

Detecting Legacy Context API

Strict mode will detect uses of the old Context API. It’ll be removed in future versions. We should move to the new one if it’s used.

Conclusion

We can use strict mode to detect uses of deprecated lifecycle methods, legacy Context API, string refs, and some code that commits unexpected side effects.

It only shows warnings in development and doesn’t affect production code.

Categories
JavaScript Vue

Introduction to Event Handling in Vue.js

Vue.js is an easy to use web app framework that we can use to develop interactive front end apps.

In this article, we’ll look at how to handle various events with Vue.js and modify an event handler’s behavior.

Listening to Events

We can use the v-on directive to listen to DOM events and run some JavaScript code when they’re triggered.

For example, we can use it as follows:

src/index.js :

new Vue({  
  el: "#app",  
  data: {  
    count: 0  
  }  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
  </head> <body>  
    <div id="app">  
      <button v-on:click="count += 1">Add 1</button>  
      <p>Count: {{count}}</p>  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>

Then when we click Add 1, the count increases by 1.

Method Event Handlers

We can also run methods when an event is triggered. This helps us a lot because we might need to runs lots of code when an event happens, so we can’t put it all in an expression in the template.

For example, we can set a method as the value of the v-on:click as follows:

src/index.js :

new Vue({  
  el: "#app",  
  methods: {  
    onClick() {  
      alert("clicked");  
    }  
  }  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
  </head> <body>  
    <div id="app">  
      <button v-on:click="onClick">Click Me</button>  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>

Then when Click Me is clicked, we get a ‘clicked’ alert box displayed.

Note that we just have to pass in the function reference, we don’t have to call it in the v-on:click directive.

Methods in Inline Handlers

In addition to passing in the method reference, we can also call methods directly with the v-on:click directive.

For example, we can write the following:

src/index.js :

new Vue({  
  el: "#app",  
  methods: {  
    onClick(message) {  
      alert(message);  
    }  
  }  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
  </head> <body>  
    <div id="app">  
      <button v-on:click="onClick('hi')">Say Hi</button>  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>

We’ll get an alert box that says ‘hi’ when we click Say Hi.

Sometimes we have to access the original DOM element that triggered the event. We can use the $event object to do this.

The $event object has the triggered event’s data, which includes the DOM element that triggered the event.

For example, we can get the ID of the button that was clicked as follows:

src/index.js :

new Vue({  
  el: "#app",  
  methods: {  
    onClick(event, message) {  
      alert(`${event.target.id} says ${message}`);  
    }  
  }  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
  </head> <body>  
    <div id="app">  
      <button id="hi-button" v-on:click="onClick($event, 'hi')">Say Hi</button>  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>

The code above passes the $event object to the onClick handler, which takes the event parameter, which is set to the $event object and get the ID of the button via event.target.id . The message string is also passed in.

Then alert is called with the string `${event.target.id} says ${message}` so when we click Say Hi, we get an alert box with that says hi-button says hi since the buttons’ ID is hi-button .

Event Modifiers

We can use event modifiers to change the behavior of event handlers.

For example, the .prevent modifier for the v-on directive will automatically run event.preventDefault on the event handler function that’s set as the value.

The .prevent modifier can be used as follows:

<form v-on:submit.prevent="onSubmit"> ... </form>

Then event.preventDefault() will be run when the onSubmit handler is run before the rest of the code for onSubmit is run.

Other event modifiers include:

  • .stop
  • .capture
  • .self
  • .once
  • .passive

.stop runs event.stopPropagation() before the rest of the event handler code is run.

.capture let us capture the event. That is, when we run the event handler in an inner element, then the same event handler will also run in the outside elements.

For example, if we have the following in src/index.js:

new Vue({  
  el: "#app",  
  data: {},  
  methods: {  
    onClick() {  
      alert("clicked");  
    }  
  }  
});

and the following in index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>Hello</title>  
    <meta charset="UTF-8" />  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
  </head><body>  
    <div id="app">  
      <div>  
        <a v-on:click.capture="onClick"> Click Me </a>  
      </div>  
    </div>  
    <script src="./src/index.js"></script>  
  </body>  
</html>

Then when we click Click Me, we’ll see the ‘clicked’ alert box since the onClick handler is called on the parent div element.

.self will only trigger the event handler if the event.target is the element itself.

.once will trigger an event handler at most once.

For example, if we have the following in src/index.js:

new Vue({  
  el: "#app",  
  data: {},  
  methods: {  
    onClick() {  
      alert("clicked");  
    }  
  }  
});

and the following in index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>Hello</title>  
    <meta charset="UTF-8" />  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
  </head> <body>  
    <div id="app">  
      <div>  
        <a v-on:click.once="onClick"> Click Me </a>  
      </div>  
    </div>  
    <script src="./src/index.js"></script>  
  </body>  
</html>

Then we only see the ‘clicked’ alert box once even though we click ‘Click me’ multiple times.

.passive will set the addEventListener ‘s passive option to true . passive set to true means that preventDefault() will never be called.

It’s used for improving performance on mobile devices.

Conclusion

We can set event handlers for DOM element events with thev-on directive.

To use it, we can pass in an expression, event handler method reference, or a call for an event handler as the value of it.

We can also get the data for the event that was triggered by the $event object, where we can get the target element of the event triggered.

Finally, we can add event modifiers to change the behavior of event handlers.

Categories
JavaScript Vue

Vue.js Transition Effects — List Transitions

Vue.js is an easy to use web app framework that we can use to develop interactive front end apps.

In this article, we’ll look at how to add transitions when rendering lists.

List Transitions

If we want to apply transitions to render multiple items simultaneously with v-for , we can use the transition-group component.

Unlike transition , it renders a span by default. We can change the element that’s rendered with the tag attribute.

Transition modes aren’t available because we aren’t alternating between mutually exclusive elements.

Elements inside are always required to have a unique key attribute.

CSS transition classes will be applied to inner elements and not the group or container itself.

List Entering/Leaving Transitions

For example, we can make add a transition when adding or removing the item to a list as follows:

src/index.js :

new Vue({  
  el: "#app",  
  data: {  
    items: [1, 2, 3],  
    nextNum: 4  
  },  
  methods: {  
    add() {  
      this.items.push(this.nextNum++);  
    },  
    remove() {  
      this.items.pop();  
    }  
  }  
});

src/style.css :

.list-enter-active,  
.list-leave-active {  
  transition: all 1s;  
}  
.list-enter,  
.list-leave-to {  
  opacity: 0;  
  transform: translateY(30px);  
}

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
    <link  
      rel="stylesheet"  
      type="text/css"  
      href="./src/styles.css"  
      media="screen"  
    />  
  </head>  
  <body>  
    <div id="app">  
      <button @click="add">Add</button>  
      <button @click="remove">Remove</button>  
      <transition-group name="list" tag="p">  
        <span v-for="item in items" :key="item">  
          {{ item }}  
        </span>  
      </transition-group>  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>

Then when we click the Add button, we see a number added to the end of the list. When we click Remove, the rightmost number is removed.

Like transition , we defined the classes prefixed with the name we specified.

Also, we specified the tag name so that we have a span element rendered for each item within the p element.

List Move Transitions

transition-group can animate the change in position, in addition, to enter and leave. We can do this with the addition of the v-move class.

Like other classes, we prefix it with the name attribute and we can also manually specify a class with the move-class attribute.

For example, we can add an effect when we shuffle the position of numbers as follows:

src/index.js :

new Vue({  
  el: "#app",  
  data: {  
    items: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]  
  },  
  methods: {  
    shuffle() {  
      this.items = _.shuffle(this.items);  
    }  
  }  
});

src/styles.css :

.flip-list-move {  
  transition: transform 1s;  
}

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>  
    <link rel="stylesheet" type="text/css" href="./src/styles.css" />  
  </head>  
  <body>  
    <div id="app">  
      <button @click="shuffle">Shuffle</button>  
      <transition-group name="flip-list" tag="div">  
        <div v-for="item in items" :key="item">  
          {{ item }}  
        </div>  
      </transition-group>  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>

When we click Shuffle, we see the shuffling is stretched slightly in time.

Vue uses FLIP to smoothly transition between elements from the old position to their new position.

They don’t work with elements set to display: inline , we have to use display: inline-block or place elements in a flexbox container.

Staggering List Transitions

We can stagger list transitions as follows:

src/index.js :

new Vue({  
  el: "#app",  
  data: {  
    items: ["foo", "bar", "baz"],  
    query: ""  
  },  
  computed: {  
    filteredItems() {  
      if (!this.query) {  
        return this.items;  
      }  
      return this.items.filter(i => i === this.query);  
    }  
  },  
  methods: {  
    beforeEnter(el) {  
      el.style.opacity = 0;  
      el.style.height = 0;  
    },  
    enter(el, done) {  
      var delay = el.dataset.index * 150;  
      setTimeout(() => {  
        Velocity(el, { opacity: 1, height: "1.6em" }, { complete: done });  
      }, delay);  
    },  
    leave(el, done) {  
      var delay = el.dataset.index * 150;  
      setTimeout(() => {  
        Velocity(el, { opacity: 0, height: 0 }, { complete: done });  
      }, delay);  
    }  
  }  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
    <script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script>  
  </head>  
  <body>  
    <div id="app">  
      <input v-model="query" />  
      <transition-group  
        name="flip-list"  
        tag="div"  
        v-bind:css="false"  
        v-on:before-enter="beforeEnter"  
        v-on:enter="enter"  
        v-on:leave="leave"  
      >  
        <div v-for="item in filteredItems" :key="item">  
          {{ item }}  
        </div>  
      </transition-group>  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>

We can see that we now have transitions when the list is being filtered.

Conclusion

We can create transitions when rendering a list with v-for like we do with v-if .

The difference is that we have to specify the tag name of the container if we don’t want to render a span.

Also, we always have to add the key attribute to each element inside.

We can have transitions when changing element position by specifying the CSS style for the v-move class, which can be renamed if we specify the class prefix or name.

Specifying enter and leave transitions or v-for is the same as specifying enter and leave transitions for v-if .

Finally, we can create transitions with JavaScript with Velocity.js just like v-if animations.

Categories
Express JavaScript Nodejs

Serve Favicons in Express Apps with serve-favicon

If we have an Express app that renders templates, we can use the serve-favicon middleware to serve Favicons.

Favicons are icons on the left side of a browser tab.

In this article, we’ll look at how to use it to display our favorite favicon in users’ browsers.

Why do we need this module?

The serve-favicon module lets us exclude requests for the favicon in our logger middleware.

It also caches the icon in memory to improve performance by reducing disk access.

In addition, it provides an ETag based on the contents of the icon, rather than file system properties.

Finally, this module serves with the most compatible Content-Type .

This module is exclusive for serving the favicon with the GET /favicon.ico request.

Installation

We can install it by running:

npm install serve-favicon

Options

The favicon function is provided by this module. It takes 2 arguments, which are path, and options and returns a middleware to serve a favicon from the given path .

The options object takes one property, which is the maxAge property. It sets the cache-control max-age directive in milliseconds. The default is 1 yeat. It also can be a string that’s accepted by the ms module.

Examples

Simple Usage

The serve-favicon middleware should come before other middleware so that it won’t conflict with other requests for favicon.ico .

For instance, we can load a favicon with serve-favicon as follows:

const express = require('express');  
const bodyParser = require('body-parser');  
const favicon = require('serve-favicon')  
const path = require('path')  
const app = express();  
app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')))  
app.use(bodyParser.json());  
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static('public'));
app.get('/', (req, res) => {  
  res.sendFile('public/index.html');  
});
app.listen(3000);

Then we get:

https://thewebdev.info/wp-content/uploads/2020/04/icon.png

Setting Max Age

We can also set the maxAge option as follows:

const express = require('express');  
const bodyParser = require('body-parser');  
const favicon = require('serve-favicon')  
const path = require('path')  
const app = express();  
const iconPath = path.join(__dirname, 'public', 'favicon.ico');  
const options = {  
  maxAge: 200 * 60 * 60 * 24 * 1000  
}  
app.use(favicon(iconPath, options));  
app.use(bodyParser.json());  
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static('public'));app.get('/', (req, res) => {  
  res.sendFile('public/index.html');  
});
app.listen(3000);

Then we set the expiry of the icon to 200 days.

Conclusion

We can use the serve-favicon middleware to cache requests for favicon and serve it instead of loading it every time when users make a request for the favicon.

The expiry can also be set so the favicon request result won’t be cached forever.

It should be included before other middleware so that it won’t conflict with other middleware that makes request for a favicon.

Categories
JavaScript Vue

Introduction to Vue.js Computed Properties and Watchers

Vue.js is an easy to use web app framework that we can use to develop interactive front end apps.

In this article, we’ll look at Vue.js computed properties and watchers.

Computed Properties

To make more template expressions more concise and reusable, we can create computed properties to compute results from existing properties as their value changes.

We can define computed properties in a Vue instance by putting them in the computed property of the options object that we pass into the Vue constructor.

For example, we can write the following in src/index.js:

new Vue({  
  el: "#app",  
  data: {  
    message: "foo"  
  },  
  computed: {  
    spelledMessage() {  
      return this.message.split("").join("-");  
    }  
  }  
});

Then we can use it like any other field in our HTML template. So in index.html, we can write:

<!DOCTYPE html>  
<html>  
  <head>  
    <title>Hello</title>  
    <meta charset="UTF-8" />  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
  </head> <body>  
    <div id="app">  
      <p>{{message}}</p>  
      <p>{{spelledMessage}}</p>  
    </div>  
    <script src="./src/index.js"></script>  
  </body>  
</html>

We should then get:

foof-o-o

on our screen.

The spelledMessage method is a getter that’s used by Vue.js. It takes the returned value of it and then put it in place of {{spelledMessage}} .

Therefore, the name of the placeholder in the template must be the same as the name of the method that returns the value that we want in the computed object.

We can also get the value from the returned Vue instance as follows:

const vm = new Vue({  
  el: "#app",  
  data: {  
    message: "foo"  
  },  
  computed: {  
    spelledMessage() {  
      return this.message.split("").join("-");  
    }  
  }  
});console.log(vm.spelledMessage);

We should see f-o-o logged from the console.log.

We can bind to computed properties in templates like any other property. Vue knows that vm.spelledMessage depends on vm.message, so the bindings will be updated when vm.message is updated.

The computed getter method doesn’t commit side effects, which makes it easy to test and understand.

Computed Caching vs Methods

One good feature of computed properties is that the result of it is cached.

There’s no caching for results returned from methods.

So instead of using methods, we should use computed properties for cases where we’re computing something from existing properties.

A computed property is only re-evaluated once a reactive property is updated.

For example, if we have:

const vm = new Vue({  
  el: "#app",  
  data: {  
    message: "foo"  
  },  
  computed: {  
    now() {  
      return Date.now();  
    }  
  }  
});

It’ll never update after its first computed since it doesn’t depend on any reactive property from the data property.

Without caching computed properties keep getting computed as reactive properties that they depend on change, which means the app gets slow as reactive properties that the computed property depends on are changing.

Computed vs Watched Property

Watch properties are useful for watching for changes in a property as the name suggests.

However, because of the caching feature of computed properties, we should use them as much as we can.

For instance, we can simplify the following:

new Vue({  
  el: "#app",  
  data: {  
    name: "Joe",  
    age: 1,  
    person: undefined  
  },  
  watch: {  
    name: {  
      immediate: true,  
      handler(newVal) {  
        this.person = `${newVal} - ${this.age}`;  
      }  
    },  
    age: {  
      immediate: true,  
      handler(newVal) {  
        this.person = `${this.name} - ${newVal}`;  
      }  
    }  
  }  
});

to:

new Vue({  
  el: "#app",  
  data: {  
    name: "Joe",  
    age: 1  
  },  
  computed: {  
    person() {  
      return `${this.name} - ${this.age}`;  
    }  
  }  
});

As we can see, the first example was much more complex. We have to set immediate to true in each property so that it’ll watch the initial value change. Then we have to define the value change handler for each reactive property.

Then in each handler, we have to set the person property so that we can combine name and age.

On the other hand, with computed properties, we only have one method which returns the fields combined in the way we want.

It’s much more convenient for us and the app that we create is also faster because of caching.

Computed Setter

We can also create a setter function for computed properties.

For example, we can write:

new Vue({  
  el: "#app",  
  data: {  
    name: "Joe",  
    age: 1  
  },  
  computed: {  
    person: {  
      get() {  
        return `${this.name} - ${this.age}`;  
      },  
      set(newValue) {  
        const [name, age] = newValue.split("-");  
        this.name = name.trim();  
        this.age = age.trim();  
      }  
    }  
  }  
});

The getter function returns the same thing as before, but now we also have a setter function.

The setter function splits the newValue, which has the computed value from the getter function, we split the result and set the result back to the corresponding reactive properties.

We can use a setter as follows. We can put the following in src/index.js:

new Vue({  
  el: "#app",  
  data: {  
    firstName: "Joe",  
    lastName: "Smith"  
  },  
  computed: {  
    name: {  
      get() {  
        return `${this.firstName} ${this.lastName}`;  
      },  
      set(newValue) {  
        const [firstName, lastName] = newValue.split(" ");  
        this.firstName = (firstName || "").trim();  
        this.lastName = (lastName || "").trim();  
      }  
    }  
  }  
});

And in index.html, we put:

<!DOCTYPE html>  
<html>  
  <head>  
    <title>Hello</title>  
    <meta charset="UTF-8" />  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
  </head> <body>  
    <div id="app">  
      <p>{{name}}</p>  
      <input type="text" v-model="name" />  
    </div>  
    <script src="./src/index.js"></script>  
  </body>  
</html>

Then when we change the value in the input, we get the new values assigned back to the firstName and lastName fields with the setter.

Conclusion

We can use computed properties to compute values from existing properties.

Returned values from computed properties are cached to reduce the amount of computation required.

Computed properties can also have setters, where we can do things with the new values returned from the computed property getter.