Categories
JavaScript React

Using the React State Hook

React is a library for creating frontend 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 the state hook to keep dynamic states in a function component.

Using the State Hook

We can use the React.useState method to create a state with a corresponding function to change the state.

For example, we can write the following code to add a hook to our app:

import React from "react";  
import ReactDOM from "react-dom";
function App() {  
  const[count, setCount] = React.useState(0); 
  return (  
    <div>  
      <button onClick={() => setCount(count + 1)}>Count {count}</button>  
    </div>  
  );  
}

In the code above, we have the React.useState hook with the default 0 passed in. It returns an array with the state, which we called count, and a function to set the state, which is called setCount.

Then in the onClick handler of the button, we can the setCount function to update the count.

Equivalent Class Example

The example above would be the same as the following class:

class App extends React.Component {  
  constructor(props) {  
    super(props);  
    this.state = {  
      count: 0  
    };  
  } 

  render() {  
    return (  
      <div>  
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>  
          Count: {this.state.count}  
        </button>  
      </div>  
    );  
  }  
}

In the code above, we have this.state initialized in the constructor with count 0. Then in the button we pass in a click event handler that calls setState to update the count state by incrementing it by 1.

Therefore, this.setState({ count: this.state.count + 1 }) is the same as setCount(count + 1) and count is the same as this.state.count.

Hooks and Function Components

A function component looks like:

const App = props => <p>foo</p>;

or:

function App(props) {  
  return <p>foo</p>;  
}

They were previously known as stateless components. However, now that React has hooks, they can keep their own state. Therefore, they should be called function components.

What’s a Hook?

A hook is a special function that lets us hook into React features. useState in the example above is a hook that lets us add React state to function components.

Declaring a State Variable

useState declares a state variable. In the example above, we have a variable called count but we can call it anything else.

useState has the same capabilities as this.state that we had in a class.

Variables disappear when the function exists but state variables are preserved by React.

The only argument for useState is the initial state. The state doesn’t have to be an object unlike classes.

We can have any type of data as the initial state.

If we want to store multiple values in state, then we’ll call useState for each kind of data.

useState always gives us the current state. It’s not only for creating the initial state.

Reading State

In the example, that we had:

import React from "react";  
import ReactDOM from "react-dom";
function App() {  
  const [count, setCount] = React.useState(0); 
  return (  
    <div>  
      <button onClick={() => setCount(count + 1)}>Count {count}</button>  
    </div>  
  );  
}

We get the current state from count returned by useState .

Updating State

Instead of calling this.setState like we do in class components, we call the setCount function directly.

Therefore, we don’t have to worry about the value of this .

What Do Square Brackets Mean?

The square brackets in:

const [count, setCount] = React.useState(0);

is the destructuring assignment operation, which means that values from an array are assigned to variables depending on the position.

The first element is assigned to the first variable, the second is assigned to the second variable, etc.

const [count, setCount] = React.useState(0);

is the same as:

const countState = React.useState(0);  
const count = countState[0];  
const setCount = countState[1];

Using Multiple State Variables

We will call useState as many times as we need to use multiple state variables.

For example, we can write:

function App() {  
  const [count, setCount = React.useState(0);  
  const [foo] = React.useState({ text: "bar" });  
  return (  
    <div>  
      <button onClick={() => setCount(count + 1)}>Count {count}</button>  
      <p>{foo.text}</p>  
    </div>  
  );

In the code above, we have 2 calls to useState to create 2 states, count and foo .

States can have object values, so we don’t have to create too many states.

Conclusion

We can use the useState hook to get and set dynamic states in a function component.

It returns the current state and a function to update the state in an array.

Then we can use them directly to display data and call the returned function to update the state.

Categories
JavaScript React

Manipulate DOM Elements in External React Components with ForwardRef

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

To manipulate DOM elements directly with React, we can create a ref, associate it to an element, and then reference that and call its methods to manipulate the DOM item directly.

In this article, we’ll look at how to pass the ref to components outside of its originating component by forwarding refs.

Forwarding refs to DOM components

We can forward refs by creating a ref and then call the forwardRef method to get the ref and then pass it into any place we want.

For example, if we have a Button component that returns a button element, and we want to get the button element from the outside component, we can write the following:

const Button = React.forwardRef((props, ref) => (  
  <button id="custom-button" ref={ref}>  
    {props.children}  
  </button>  
));

class App extends React.Component {  
  constructor(props) {  
    super(props);  
    this.state = {};  
    this.buttonRef = React.createRef();  
  } componentDidMount() {  
    this.buttonRef.current.focus();  
  } render() {  
    return <Button ref={this.buttonRef}>Click Me</Button>;  
  }  
}

In the code above, we have a Button component created by using the React.forwardRef method with a callback passed in.

The callback has a props parameter which has the props that are passed in from the parent component, and the ref object which has the ref that’s passed in from the parent component.

Then we set the ref prop of the button element to the ref from the parameter.

Then we can create a new ref in the App component by calling React.createRef in App ‘s constructor. Then we pass that into the ref prop of Button so that we can access the ForwardRef from the button element.

This means the this.buttonRef is referencing the button element because we passed it into Button , which passes this.buttonRef into the button element via the callback we passed into React.forwardRef .

Then in the App component, we call:

this.buttonRef.current.focus();

in componentDidMount to focus the button in Button from App .

Forwarding refs in Higher-Order Components

We can also forward refs in high-order components. To do this, we write something like the following:

const Button = ({ forwardedRef, children }) => (  
  <button ref={forwardedRef}>{children}</button>  
);

function logProps(Component) {  
  class LogProps extends React.Component {  
    componentDidMount() {  
      console.log(this.props);  
    } 

    render() {  
      const { forwardedRef, ...rest } = this.props;  
      return <Component forwardedRef={forwardedRef} {...rest} />;  
    }  
  } 

  return React.forwardRef((props, ref) => {  
    return <LogProps {...props} forwardedRef={ref} />;  
  });  
}

class App extends React.Component {  
  constructor(props) {  
    super(props);  
    this.buttonRef = React.createRef();  
  } 

  componentDidMount() {  
    this.buttonRef.current.focus();  
  } 

  render() {  
    const ButtonLogProp = logProps(Button);  
    return <ButtonLogProp ref={this.buttonRef}>Click Me</ButtonLogProp>;  
  }  
}

In the code above, we have the logProps higher-order component. The logProps component takes a Component .

logProps return a component with the forwarded refs passed in by calling React.forwardRef with a callback that returns LogProps .

In the App component we pass this.buttonRef as the value to ButtonLogProp .

ButtonLogProp is created by calling logProps with the Button component passed in. This means Component is Button in logProp .

Component, which is Button is then returned in the render method of the LogProp component.

At the end of the logProp higher-order component, we return the component with returned from React.forwardRef . The callback we pass into forwardRef returns the LogProps component with the props including the forwarded ref passed in.

All the props will then reach the Button component, which sets the ref of the button element to the this.buttonRef , which is first passed into logProp , then passed into LogProp , and React.forwardRef returns a component with the forwarded ref passed to the Button component, and then into the button element.

In other words, we passed the ref from App , to logProp , to LogProp , then forwarded with React.forwardRef to Button and then to button .

Conclusion

We can use refs from external components by forwarding refs. This lets us manipulate DOM elements from external components within a component.

Forwarding refs also works with higher-order components. All we have to do is to return the component we want to return in the higher-order component in the React.forwardRef callback with the forwarded ref passed in.

Categories
JavaScript Vue

Vue.js Components — Slots and Dynamic Components

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 distributing components with slots and dynamic components.

Distributing Components with Slots

We can pass content in components by putting text between the opening and closing tags.

To do this, we can add a slot to our component with the slot element.

For example, we can use it as follows:

src/index.js :

Vue.component("error-box", {  
  template: `  
    <div v-bind:style="{color: 'red'}">  
      <slot></slot>  
    </div>  
  `  
});

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

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">  
      <error-box>Error</error-box>  
    </div> <script src="src/index.js"></script>  
  </body>  
</html>

The text Error that we put between the error-box tags replace the slot tag, so we get the word ‘Error’ in red displayed.

Dynamic Components

We can switch dynamically between components by using v-bind:is .

The value of v-bind:is can contain either the name of a registered component or a component’s options object.

For example, we can use it as follows:

src/index.js :

Vue.component("tab-foo", {  
  template: "<div>Foo</div>"  
});

Vue.component("tab-bar", {  
  template: "<div>Bar</div>"  
});

Vue.component("tab-baz", {  
  template: "<div>Baz</div>"  
});

new Vue({  
  el: "#app",  
  data: {  
    currentTab: "foo"  
  },  
  computed: {  
    currentTabComponent() {  
      return `tab-${this.currentTab.toLowerCase()}`;  
    }  
  }  
});

In the code above, we created 3 components, and in the root Vue instance, we have the currentTab field so that we can add buttons to change the content in the HTML template.

The currentTabComponent will be updated as this.currentTab changes, which we’ll set the value of with buttons in the template.

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 @click='currentTab = "foo"'>Foo</button>  
      <button @click='currentTab = "bar"'>Bar</button>  
      <button @click='currentTab = "baz"'>Baz</button>  
      <component v-bind:is="currentTabComponent"></component>  
    </div> <script src="src/index.js"></script>  
  </body>  
</html>

In the template above, we have 3 buttons with click event handlers to set the currentTab value, which will also set the currentTabComponent property as currentTab changes.

Since we passed currentTabComponent to v-bind:is , the component element will replace the component with the name set in currentTabComponent .

So when we click the Foo button we get Foo, when we click the Bar button we get Bar, and when we click the Baz button we get Baz.

We can pass in an object to v-bind:is as follows:

src/index.js :

new Vue({  
  el: "#app",  
  data: {  
    tabBar: {  
      template: "<div>Bar</div>"  
    }  
  }  
});

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">  
      <component v-bind:is="tabBar"></component>  
    </div> <script src="src/index.js"></script>  
  </body>  
</html>

We passed in the tabBar object as the value of v-bind:is directive.

DOM Template Parsing Issues

Some HTML elements have restrictions on what can be inside them. For example, ul must have li elements inside them.

We can nest whatever element we want with the is attribute.

For example, we can use it as follows:

src/index.js :

Vue.component("list-item", {  
  template: "<div>Foo</div>"  
});

new Vue({  
  el: "#app"  
});

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">  
      <ul>  
        <li is="list-item"></li>  
      </ul>  
    </div> <script src="src/index.js"></script>  
  </body>  
</html>

The code above sets the list-item component as the component inside the li element.

This limitation doesn’t apply if we’re using string templates from one of the following sources:

  • String templates (e.g. template: '...')
  • Single-file (.vue) components
  • <script type="text/x-template">

Conclusion

We can get the content of items in between the opening and closing tags of our component with the slot element.

The component element let us change the component dynamically by passing in a string name for the component.

We can pass an object or a string with the component name to v-bind:is .

Categories
JavaScript Vue

Introduction to Vue.js Directives

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 manipulate the DOM with Vue.js directives.

Basics

Vue lets us register or own custom directives, in addition to using built-in ones like v-for and v-if .

It’s useful for low-level DOM manipulation that can’t easily be done with components.

For example, we can make one as follows:

src/index.js :

Vue.directive("focus", {  
  inserted(el) {  
    el.focus();  
  }  
});
const vm = new Vue({  
  el: "#app"  
});

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">  
      <input v-focus />  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>

In the code above, we defined the focus directive, which is referenced by adding a v- prefix to it.

The focus directive calls focus on the DOM element when it’s inserted into the DOM. The inserted method is a hook that handles the situation when the element that has the directive applied is inserted into the DOM.

The el parameter has the DOM element, which is why we can call the focus method on it.

Therefore, when we load the page, we’ll see that the input element is focused. This is the work of the focus directive.

The code above registered the directive globally. We can also register the directive locally as follows:

src/index.js :

const focus = {  
  inserted(el) {  
    el.focus();  
  }  
};

const vm = new Vue({  
  el: "#app",  
  directives: {  
    focus  
  }  
});

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">  
      <input v-focus />  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>

The focus directive will then only be available to the component that it’s registered in.

Hook Functions

A directive can have the following hook functions. They’re all optional.

  • bind — called only once when the directive is first bound to the element. It’s used for one-time setup work
  • inserted — called when the bound element is inserted into its parent node. It guarantees the parent node presence.
  • updarted — calls after the containing component VNode has updated but possibly before children have updated. VNode is a node in the virtual DOM, it stands for virtual node.
  • componentUpdated — called when the containing component’s VNode and VNodes of its children are updated
  • unbind — called only once when the directive is unbound from the element

Directive Hook Arguments

The hooks above take the following arguments:

el

The element the directive is bound to. It can used to manipulate the DOM

binding

An object containing the following properties:

  • name — name of the directive without the v- prefix
  • value — value passed to the directive. For example, if we have v-foo='1' then the value is 1 .
  • oldValue — the previous value. This is only available in update and compoentUpdated . It’s available whether or not the value has changed.
  • expression — the expression of the binding as a string. For example, if we have v-foo='1 + 2' then it’s 1 + 2 .
  • arg —the argument passed into the directive. For example, if we have v-foo:bar then the arg is ‘bar‘.
  • modifiers — an object with modifiers. If we have v-foo.bar.baz then it would be { bae: true, baz: true } .

Everything other than el are read-only.

For example, we can display the data that are passed from the parameters as follows:

src/index.js :

const foo = {  
  inserted(el, binding, vnode) {  
    const stringify = JSON.stringify;  
    el.innerHTML = `  
      name:   
        ${stringify(binding.name)}  
      <br>  
      value:    
       ${stringify(binding.value)}  
      <br>  
      expression:  
        ${stringify(binding.expression)}  
      <br>  
      argument  
       ${stringify(binding.arg)}  
      <br>  
      modifiers:  
        ${stringify(binding.modifiers)}  
      <br>  
      vnode keys:  
       ${Object.keys(vnode).join(", ")}`;  
  }  
};

const vm = new Vue({  
  el: "#app",  
  directives: {  
    foo  
  }  
});

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">  
      <div v-foo:bar.baz="1 + 2"></div>  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>

Then we get:

name: "foo"  
value: 3  
expression: "1 + 2"  
argument "bar"  
modifiers: {"baz":true}  
vnode keys: tag, data, children, text, elm, ns, context, fnContext, fnOptions, fnScopeId, key, componentOptions, componentInstance, parent, raw, isStatic, isRootInsert, isComment, isCloned, isOnce, asyncFactory, asyncMeta, isAsyncPlaceholder

Conclusion

We can define our own Vue directives to manipulate DOM elements by binding them to specific DOM elements and then run the elements’ methods.

It works by running hooks when certain during certain stages of virtual node manipulation by Vue.

The hooks take the DOM element object as the first argument and a binding object which has the data about the directive like name, the value passed in, modifiers and arguments.

Categories
Express JavaScript Nodejs

Add Basic Authentication to an Express App

To add basic auth capabilities to an Express app, we can use the express-basic-auth package.

With it, we can check for a given username and password in the URL in our protected routes.

In this article, we’ll take a look at how to use it.

How to Install

express-basic-auth is available as a Node package, we can install it by running:

npm install express-basic-auth

Basic Usage

We can use it as follows:

const express = require('express');  
const basicAuth = require('express-basic-auth')  
const app = express();
app.use(basicAuth({  
    users: { 'admin': 'supersecret' }  
}))

app.get('/', (req, res) => {  
  res.send('authorized');  
});

app.listen(3000, () => console.log('server started'));

In the code above, we included the basicAuth middleware from express-basic-auth from in our app.

Then we can call app.use with an object that has the users property with the usernames as the keys and the corresponding passwords as the values.

Then if we make a GET request to a URL like:

https://admin:supersecret@ThistleDarkExponents--five-nine.repl.co

Then we’ll get the authorized response back since the username and password matches what we listed in the object in our app.

Otherwise, we’ll get a 401 response and a configurable body, which is empty by default.

Custom Authorization

We can also pass in our own authorizer function to check for credentials that we want.

We shouldn’t use standard string comparison with == or === when comparing user input with sercet credentials since it’ll make our app vulenrable to timing attacks.

Timing attacks are a side-channel attack where the attacker tries to compromise a system by analyzing the time taken to run cryptographic algorithms.

We should use the safeCompare method provided by the package instead.

Also, we should use bitwise logic operators instead of standard ones for the same reason.

For example, we can use the following:

const express = require('express');  
const basicAuth = require('express-basic-auth')  
const app = express();
app.use(basicAuth({  
  authorizer: (username, password) => {  
    const userMatches = basicAuth.safeCompare(username, 'admin')  
    const passwordMatches = basicAuth.safeCompare(password, 'supersecret')  
    return userMatches & passwordMatches  
  }  
}))

app.get('/', (req, res) => {  
  res.send('authorized');  
});

app.listen(3000, () => console.log('server started'));

In the code above, we have a function that calls safeCompare to match the username and password respectively and then use the AND bitwise operator to combine the 2 to make sure that both are true .

Async Authorization

We can set the authorizeAsync option to true and set a function with a cb parameter for the callback as the authorizer function to check credentials asynchronously:

const express = require('express');  
const basicAuth = require('express-basic-auth')  
const app = express();
app.use(basicAuth({  
  authorizer: (username, password, cb) => {  
    const userMatches = basicAuth.safeCompare(username, 'admin')  
    const passwordMatches = basicAuth.safeCompare(password, 'supersecret')  
    if (userMatches & passwordMatches)  
      return cb(null, true)  
    else  
      return cb(null, false)  
  },  
  authorizeAsync: true,  
}))

app.get('/', (req, res) => {  
  res.send('authorized');  
});

app.listen(3000, () => console.log('server started'));

We return the cb callback call instead of returning the result directly in our authorizer function.

Unauthorized Response Body

We can set the unauthorizedResponse property to a function that returns a response that we want to show when a credential check failed.

For example, we can write:

const express = require('express');  
const basicAuth = require('express-basic-auth')  
const app = express();  
app.use(basicAuth({  
  users: { 'admin': 'supersecret' },  
  unauthorizedResponse: (req) => {  
    return `unauthorized. ip: ${req.ip}`  
  }  
}))  
app.get('/', (req, res) => {  
  res.send('authorized');  
});  
app.listen(3000, () => console.log('server started'));

to return something like:

unauthorized. ip: ::ffff:172.18.0.1

when basic authentication fails.

The function we set unauthorizedResponse to takes the Express request object, so we can use any properties from there in the function.

Challenge

We can make browsers show a popup so that users can enter credentials for authentication by add a challenge: true option to the object.

In addition, we set the realm to identify the system to authenticate against and can be used to save credentials of the challenge by passing a static or a function that gets passed the request object and is expected to return the challenge:

const express = require('express');  
const basicAuth = require('express-basic-auth')  
const app = express();app.use(basicAuth({  
  users: { 'admin': 'supersecret' },  
  challenge: true,  
  realm: 'foo',  
}))

app.get('/', (req, res) => {  
  res.send('authorized');  
});

app.listen(3000, () => console.log('server started'));

With the code above, we should get a dialog box to enter the username and password when we load the / page.

Conclusion

Adding basic auth to an Express app is easy with the express-basic-auth package.

It lets us add a list of valid credentials or use a function to validate credentials.

We can also let users enter the username and password and display custom content when the user is unauthorized.