Categories
JavaScript React

Use React to Display Images in a Grid Like Google and Flickr

If you use image search websites like Google Image Search or Flickr, you will notice that their images display in a grid that looks like a wall of bricks. The images are uneven in height, but equal in width. This is called the masonry effect because it looks like a wall of bricks.

To implement the masonry effect, we have to set the width of the image proportional to the screen width and set the image height to be proportional to the aspect ratio of the image.

This is a pain to do if it’s done without any libraries, so people have made libraries to create this effect.

In this article, we will build a photo app that allows users to search for images and display images in a masonry grid. The image grid will have infinite scroll to get more images. We will build it with React and the React Masonry Component library. For infinite scrolling, we will use the React Infinite Scroller library. We will wrap the React Infinite Scroller outside the React Masonry Component to get infinite scrolling with the masonry effect when displaying images.

Our app will display images from the Pixabay API. You can view the API documentation and register for a key at https://pixabay.com/api/docs/

To start, we run Create React App to create the app. Run npx create-react-app photo-app to create the initial code for the app.

Then we install our own libraries. We need React Infinite Scroller, React Masonry Component, Bootstrap for styling, Axios for making HTTP requests, Formik and Yup for form value data binding and form validation, and React Router for routing URLs to our pages.

To install all the packages, run:

npm i axios bootstrap formik react-bootstrap react-infinite-scroller react-masonry-component react-router-dom yup

to install all the packages.

With all the packages installed, we can start building the app. First start with replacing the code in App.js with:

import React from "react";  
import { Router, Route } from "react-router-dom";  
import HomePage from "./HomePage";  
import { createBrowserHistory as createHistory } from "history";  
import TopBar from "./TopBar";  
import ImageSearchPage from "./ImageSearchPage";  
import "./App.css";  
const history = createHistory();

function App() {  
  return (  
    <div className="App">  
      <Router history={history}>  
        <TopBar />  
        <Route path="/" exact component={HomePage} />  
        <Route path="/imagesearch" exact component={ImageSearchPage} />  
      </Router>  
    </div>  
  );  
}

export default App;

to add the top bar and the routes for our app into the entry point of the app.

Next remove all the code in App.css and add:

.page {  
  padding: 20px;  
}

to add padding to our pages.

Then we set our React Masonry Component options by creating a exports.js in the src folder and add:

export const masonryOptions = {  
  fitWidth: true,  
  columnWidth: 300,  
  gutter: 5  
};

These options are very important. We need to set fitWidth to true to center our grid. columnWidth must be a number to get constant width. It will scale according to screen size only with constant width. The gutter value is the margin between items.

The full list of options are at https://masonry.desandro.com/options.html

Next we create our app’s home page by creating HomePage.js in the src folder and add:

import React from "react";  
import { getImages } from "./request";  
import InfiniteScroll from "react-infinite-scroller";  
import Masonry from "react-masonry-component";  
import "./HomePage.css";  
import { masonryOptions } from "./exports";

function HomePage() {  
  const [images, setImages] = React.useState([]);  
  const [page, setPage] = React.useState(1);  
  const [total, setTotal] = React.useState(0);  
  const [initialized, setInitialized] = React.useState(false); 
  const getAllImages = async (pg = 1) => {  
    const response = await getImages(page);  
    let imgs = images.concat(response.data.hits);  
    setImages(imgs);  
    setTotal(response.data.total);  
    pg++;  
    setPage(pg);  
  }; 

  React.useEffect(() => {  
    if (!initialized) {  
      getAllImages();  
      setInitialized(true);  
    }  
  }); 

  return (  
    <div className="page">  
      <h1 className="text-center">Home</h1>  
      <InfiniteScroll  
        pageStart={1}  
        loadMore={getAllImages}  
        hasMore={total > images.length}  
      >  
        <Masonry  
          className={"grid"}  
          elementType={"div"}  
          options={masonryOptions}  
          disableImagesLoaded={false}  
          updateOnEachImageLoad={false}  
        >  
          {images.map((img, i) => {  
            return (  
              <div key={i}>  
                <img src={img.previewURL} style={{ width: 300 }} />  
              </div>  
            );  
          })}  
        </Masonry>  
      </InfiniteScroll>  
    </div>  
  );  
}  
export default HomePage;

In the home page, we just get the images when the page loads. When the user scroll down, we load more images by adding 1 to the currentpage value and get the image with the page number.

With the InfiniteScroll component, which is provided by React Infinite Scroll, wrapped outside the Masonry component, which is provided by React Masonry Component, we display our images in a grid, and also display more when the user scrolls down until the length of the images array is greater than or equal to the total, which is from the total field given by the Pixabay API’s results.

We load images when the page loads by checking if initialized flag is true, we only load images on page load if initialized is false and the when the request is first made to the API and succeeds, then we set initialized flag to true to stop requests from being made on every render.

Next we create a image search page by creating the ImageSearchPage.js file and adding the following:

import React from "react";  
import { Formik } from "formik";  
import Form from "react-bootstrap/Form";  
import Col from "react-bootstrap/Col";  
import Button from "react-bootstrap/Button";  
import * as yup from "yup";  
import InfiniteScroll from "react-infinite-scroller";  
import Masonry from "react-masonry-component";  
import { masonryOptions } from "./exports";  
import { searchImages } from "./request";

const schema = yup.object({  
  keyword: yup.string().required("Keyword is required")  
});

function ImageSearchPage() {  
  const [images, setImages] = React.useState([]);  
  const [keyword, setKeyword] = React.useState([]);  
  const [page, setPage] = React.useState(1);  
  const [total, setTotal] = React.useState(0);  
  const [searching, setSearching] = React.useState(false); 
  
  const handleSubmit = async evt => {  
    const isValid = await schema.validate(evt);  
    if (!isValid) {  
      return;  
    }  
    setKeyword(evt.keyword);  
    searchAllImages(evt.keyword, 1);  
  }; 

  const searchAllImages = async (keyword, pg = 1) => {  
    setSearching(true); 
    const response = await searchImages(keyword, page);  
    let imgs = response.data.hits;  
    setImages(imgs);  
    setTotal(response.data.total);  
    setPage(pg);  
  }; 

  const getMoreImages = async () => {  
    let pg = page;  
    pg++;  
    const response = await searchImages(keyword, pg);  
    const imgs = images.concat(response.data.hits);  
    setImages(imgs);  
    setTotal(response.data.total);  
    setPage(pg);  
  }; 

  React.useEffect(() => {}); 
  
  return (  
    <div className="page">  
      <h1 className="text-center">Search</h1>  
      <Formik validationSchema={schema} onSubmit={handleSubmit}>  
        {({  
          handleSubmit,  
          handleChange,  
          handleBlur,  
          values,  
          touched,  
          isInvalid,  
          errors  
        }) => (  
          <Form noValidate onSubmit={handleSubmit}>  
            <Form.Row>  
              <Form.Group as={Col} md="12" controlId="keyword">  
                <Form.Label>Keyword</Form.Label>  
                <Form.Control  
                  type="text"  
                  name="keyword"  
                  placeholder="Keyword"  
                  value={values.keyword || ""}  
                  onChange={handleChange}  
                  isInvalid={touched.keyword && errors.keyword}  
                />  
                <Form.Control.Feedback type="invalid">  
                  {errors.keyword}  
                </Form.Control.Feedback>  
              </Form.Group>  
            </Form.Row>  
            <Button type="submit" style={{ marginRight: "10px" }}>  
              Search  
            </Button>  
          </Form>  
        )}  
      </Formik>  
      <br />  
      <InfiniteScroll  
        pageStart={1}  
        loadMore={getMoreImages}  
        hasMore={searching && total > images.length}  
      >  
        <Masonry  
          className={"grid"}  
          elementType={"div"}  
          options={masonryOptions}  
          disableImagesLoaded={false}  
          updateOnEachImageLoad={false}  
        >  
          {images.map((img, i) => {  
            return (  
              <div key={i}>  
                <img src={img.previewURL} style={{ width: 300 }} />  
              </div>  
            );  
          })}  
        </Masonry>  
      </InfiniteScroll>  
    </div>  
  );  
}  
export default ImageSearchPage;

We do not load images on the first load on this page. Instead, the user enters a search term in the form and when the user clicks the Search button, then handleSubmit is called. The evt object has the form values, which is updated by the Formik component. Yup provides the form validation object with the schema object, we just check if keyword is required.

In the handlesubmit function, we get the evt object, which we validate against the schema by callingschema.validate, which returns a promise. If the promise returns to something truthy, then we proceed with making the request to the Pixabay API with the search keyword and page number.

We have the same setup as the home page for the infinite scroll and masonry effect image grid. The only difference is that we call the searchAllImages function which has similar logic as the getAllImages function, except that we pass in the keyword parameter in addition to the page parameter. We set the imgs variable to the array returned from the Pixabay API and set the images by calling setImages. We also set the page by calling setPage.

When the user scrolls far enough down that content runs out, the getMoreImages function is called when images.length is less than the total. The total is set by getting the total field from the API.

We use masonryOptions from exports.js just like in the home page and display images the same way.

Next create request.js in the src folder to add the code for making HTTP requests to the back end, like so:

const axios = require("axios");  
const APIURL = "https://pixabay.com/api";

export const getImages = (page = 1) =>  
  axios.get(`${APIURL}/?page=${page}&key=${process.env.REACT_APP_APIKEY}`);

export const searchImages = (keyword, page = 1) =>  
  axios.get(  
    `${APIURL}/?page=${page}&key=${process.env.REACT_APP_APIKEY}&q=${keyword}`  
  );

We have the getImages for just getting images and searchImages that also sends the search term to the API. process.env.REACT_APP_APIKEY is from setting the REACT_APP_APIKEY variable in the .env file in the project’s root folder.

Next create TopBar.js in the src folder and add:

import React from "react";  
import Navbar from "react-bootstrap/Navbar";  
import Nav from "react-bootstrap/Nav";  
import { withRouter } from "react-router-dom";

function TopBar({ location }) {  
  React.useEffect(() => {}); 

  return (  
    <Navbar bg="primary" expand="lg" variant="dark">  
      <Navbar.Brand href="#home">Photo App</Navbar.Brand>  
      <Navbar.Toggle aria-controls="basic-navbar-nav" />  
      <Navbar.Collapse id="basic-navbar-nav">  
        <Nav className="mr-auto">  
          <Nav.Link href="/" active={location.pathname == "/"}>  
            Home  
          </Nav.Link>  
          <Nav.Link  
            href="/imagesearch"  
            active={location.pathname == "/imagesearch"}  
          >  
            Search  
          </Nav.Link>  
        </Nav>  
      </Navbar.Collapse>  
    </Navbar>  
  );  
}  

export default withRouter(TopBar);

This contains the React Bootstrap Navbar to show a top bar with a link to the home page and the name of the app. We check the location.pathname to highlight the right links by setting the active prop, where the location prop is provided by React Router by wrapping the withRouter function outside the TopBar component.

Finally, in index.js , we replace the existing code with:

<!DOCTYPE html>  
<html lang="en">  
  <head>  
    <meta charset="utf-8" />  
    <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />  
    <meta name="viewport" content="width=device-width, initial-scale=1" />  
    <meta name="theme-color" content="#000000" />  
    <meta  
      name="description"  
      content="Web site created using create-react-app"  
    />  
    <link rel="apple-touch-icon" href="logo192.png" />  
    <!--  
      manifest.json provides metadata used when your web app is installed on a  
      user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/ 
    -->  
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />  
    <!--  
      Notice the use of %PUBLIC_URL% in the tags above.  
      It will be replaced with the URL of the `public` folder during the build.  
      Only files inside the `public` folder can be referenced from the HTML.Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC\_URL%/favicon.ico" will  
      work correctly both with client-side routing and a non-root public URL.  
      Learn how to configure a non-root public URL by running `npm run build`.  
    -->  
    <title>Photo App</title>  
    <link  
      rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"  
      integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T"  
      crossorigin="anonymous"  
    />  
  </head>  
  <body>  
    <noscript>You need to enable JavaScript to run this app.</noscript>  
    <div id="root"></div>  
    <!--  
      This HTML file is a template.  
      If you open it directly in the browser, you will see an empty page. You can add webfonts, meta tags, or analytics to this file.  
      The build step will place the bundled scripts into the <body> tag. To begin the development, run `npm start` or `yarn start`.  
      To create a production bundle, use `npm run build` or `yarn build`.  
    -->  
  </body>  
</html>

to add the Bootstrap CSS and change the title.

Categories
JavaScript Mistakes

JavaScript Mistakes You May be Making

JavaScript is a language that’s friendlier than many other programming languages in the world. However, it’s still very easy to make mistakes when writing JavaScript code through misunderstanding or overlooking stuff that we already know. By avoiding some of the mistakes below, we can make our lives easier by preventing bugs and typos in our code that bog us down with unexpected results.


Confusing Undefined and Null

JavaScript has both undefined and null for non-values. However, there are quite a few differences between the two. undefined means that the variable may have been declared, but nothing is set to it. A variable can also be explicitly set as undefined. The type of an undefined variable, when checking the type with the typeof operator, will get us the type 'undefined'. Functions that don’t return anything returns undefined. On the other hand, null values have to be explicitly set by functions that return null or just set directly to a variable. When we check an object that has the null value set, we’ll find that the type of it is'object' if a variable has the null value.

For this reason, it’s probably easier to stick to undefined whenever we can when we’re setting variable values to non-values. It reduces confusion and we only have to check that the type of a variable is 'undefined' to see whether it’s undefined. That’s less painful than having two checks, for both null and undefined.

To write functions that return undefined, we don’t have to do anything like the following example:

const f = () => {}

To set a variable that was assigned some other value to undefined, we can write:

x = undefined;

To check if a property value is undefine, we can write:

typeof obj.prop === 'undefined'

or

obj.prop === undefined

To check if a variable is undefined, we can write the following code:

typeof x === 'undefined'

A declared variable that hasn’t been assigned anything automatically has the value undefined.

If we have to check for null, then we can write:

obj.prop === null

or

x === null

for variables. We can’t use the typeof operator for checking null because the data type of null is 'object'.

<img class="do t u hm ak" src="https://miro.medium.com/max/10084/0*79d0pk1RCiMWq6dC" width="5042" height="3151" role="presentation"/>

Photo by Mikhail Vasilyev on Unsplash


Confusing Addition and Concatenation

In JavaScript, the + operator is used for both adding two numbers and concatenating strings together. Because JavaScript is a dynamic language, the operands are all automatically converted to the same type before the operation is applied. For example, if we have:

let x = 1 + 1;

then we get two because they’re both numbers. The + operation was used for addition like we expected. However, if we have the following expression:

let x = 1 + '1';

then we get '11' because the first operand was coerced into a string before the + operation is applied. The + operation was used for concatenation instead of addition. When we use the + operator on multiple variables, this makes knowing the type even harder. For example, if we have:

let x = 1;  
let y = 2;  
let z = x + y;

as we expect, we get three because x and y are both numbers. On the other hand, if we have:

let x = 1;  
let y = '2';  
let z = x + y;

then we get '12' because y is a string, so the + operator was used for concatenation instead. To solve this issue, we should convert all the operands to numbers first before using them with the + operator. For example, we should rewrite the above example into the following:

let x = 1;  
let y = '2';  
let z = Number(x) + Number(y);

The code above will get us 3 as the value of z since we converted them both to numbers with the Number factory function first. The Number function takes in any object and returns a number if it can be parsed into a number, or NaN otherwise. An alternative way to do this is to use the new Number(...).valueOf() function, as we do in the following code:

let x = 1;  
let y = '2';  
let z = new Number(x).valueOf() + new Number(y).valueOf();

Since new Number(...) is a constructor that creates an object type, we want to use the valueOf function to convert it back to a primitive type to make sure that what we get is a number type. A shorter way to do this is to write:

let x = 1;  
let y = '2';  
let z = +x + +y;

The + sign in front of a single operand will try to convert the single operand into a number or toNaN if it can’t be converted into a number. It does the same thing as the Number function. We can also convert a variable to a particular type of number. The Number object has a parseInt function to convert a string or object into an integer and a parseFloat function to convert a string or object into a floating-point number. parseInt takes the object you want to convert to a number as the first argument. It also takes a radix as an optional second argument, which is the base of the mathematical numeral systems. If the string starts with 0x, then the radix will be set to 16. If the string starts with anything else, then the radix will be set to 10.

We can use them as in the following examples:

let x = 1;  
let y = '2';  
let z = Number.parseInt(x) + Number.parseInt(y)

Also, we can use the parseFloat function as in the following code:

let x = 1;  
let y = '2';  
let z = Number.parseFloat(x) + Number.parseFloat(y)

We will get 3 in both of the examples above.


Breaking Return Statements Into Multiple Lines

JavaScript closes a statement at the end, so one line code is considered distinct from the other. For example, if we have:

const add = (a, b) => {  
  return  
  a + b;  
}

we get undefined if we run console.log(add(1, 2)); since we ran the return statement, which ended the function execution, before a + b is run. Therefore, a + b will never be run in this function. To fix this, we either have to put the return statement all in one line or use parentheses to surround what we want to return. For example, we can write:

const add = (a, b) => {  
  return a + b;  
}

This will log 3 if we run console.log(add(1, 2)); since we are actually returning the computed result in the function. We can also write:

const add = (a, b) => {  
  return (  
    a + b  
  );  
}

This is handy for returning expressions that might be longer than one line. This will also log 3 if we run console.log(add(1, 2));. For arrow functions, we can also write:

const add = (a, b) => a + b

for single-line functions since the return statement is implicit for single-line arrow functions. We can also write:

const add = (a, b) => (a + b)

to get the same thing. This also works for single-line arrow functions.

In JavaScript, if a statement is incomplete, like the first line of:

const power = (a) => {  
  const  
    power = 10;  
  return a ** 10;  
}

inside the function then the JavaScript interpreter will run the first line together with the second line to get the full statement. So:

const  
  power = 10;

is the same as:

const power = 10;

However, for complete statements like return statements, the JavaScript interpreter will treat them as separate lines. So:

return   
  a ** 10;

is not the same as:

return a ** 10;

Even though JavaScript is a friendly language, it’s still very easy to make mistakes when writing JavaScript code. It’s easy to confuse undefined and null when we aren’t familiar with JavaScript. Because of the dynamic typing nature of JavaScript, operators like the + operator that can do multiple things can easily be converted to a type we don’t expect and produce the wrong result. Also, if statements can be complete on their own, then they shouldn’t be written in their own lines if we want both lines to be together.

Categories
JavaScript

Handy Tools for Writing JavaScript Apps You May Have Missed

Since JavaScript is such a popular language and the language used by all front end web applications in some form, there’re lots of great tools to help you write high-quality JavaScript applications easily. The ecosystem of tools gets bigger and bigger every day, and more tools are available than ever before for building and debugging JavaScript applications.

ESLint

ESLint is a linting tool that checks for code quality issues like styling, lengths of functions, etc. It is used to keep formatting code structure consistent throughout the code base and eliminate issues with inconsistent formatting, bad usage of JavaScript code like double equals and triple equals, and many other things. They can also be used to identify syntax errors and simple bugs. ESLint has a huge list of rules that it checks for and it’s configurable with a text file.

To run ESLint, we can install it via NPM either per project or globally. Configuration can be done with the file that has the list of rules to enable or disable in JSON. The file is called .eslintrc and the rule is defined per project. In the file, we have something like:

{  
  "rules": {  
    "semi": ["error", "always"],  
    "quotes": ["error", "double"]  
  }  
}

This defines the rules to enable or disable and set the level of reporting. error means that it will be reported as an error. It can also be set as a warning or turned off altogether with the off option. There are also preset rules made for it like the eslint:recommended rules built into the package or the AirBNB styling rules which can be installed by use theeslint-config-airbnb Node package.

The details are located at https://www.npmjs.com/package/eslint-config-airbnb for the AirBNB package, and the default ESLint recommended rules are located at https://eslint.org/docs/rules/

As we can see from https://eslint.org/docs/rules/ there’re tons of rules in styling JavaScript code. There’re rules that are related to spacing, semicolons, arrays, new lines, indentation, case of variables, commas, etc. The list of rules you can tweak are huge.

When you run ESLint, it will go through all the rules you enabled and check the files. Then you will get a list of styling issues that it identifies and notify you of them. Also, you can set it to fix them automatically so you don’t have to. It can’t fix everything automatically, but it will try its best to do so.

Browser Developer Console

The browser developer’s console is a front end developer’s best friend. It allows you to inspect each element individual to see its computed styles, which are styles applied to the elements that are from external CSS files, inline styles, and style tags together. It allows you to see the HTML document that is rendered from the JavaScript and watch the DOM tree change as the page is changing. This is great because it allows you to see what’s changing when the page is being changed by anything. You can also pause execution or set breakpoints so that you can have time to take a close look at the change you want before the change is gone.

It’s easy to fiddle with the CSS styles before making changes in your code. This saves a lot of time because you don’t have to keep fiddling with the code and refreshing until you see what you want on the screen. To do this in Chrome developer console, we just right click on the element you want and then click Inspect. This should take us to the Elements tab, then in there, we see the Styles tab near the bottom of the screen. In there, you can enter whatever you want and then you can see what you get immediately. Whatever change you made here isn’t saved in your code, so if you want to make the change permanent, you have to copy them in your code. If you made a mess and can’t go back to what you want, you can just refresh and start over. It also has a diagram of the box model for margins and paddings and also shows all the event listeners that are attached to the element via the Event Listeners tab, which is right beside the Styles tab. There’s also the Properties tab, which has all the properties of the element you’re inspecting listed. This is great since you don’t have to add console log or do run any commands in the console to get the information. The Elements tab also lets you fiddle with the HTML of the elements directly. This is very convenient because again you can fiddle with the page structure before committing to changing anything in your code.

In the Console tab of the Chrome developer console. You can type in commands and see the output returned. The output of the console.log statements that you put in your code also shows up here when the part of the code loads. If you want to inspect the properties of global variables, you can enter the name of the global variables here and see the dump of the content of the global variable you want to inspect. There’s also the Preserve Log option for preserving the log output after you refresh, and the Autocomplete from history option to see the toggle on or off autocomplete of the code you’re typing in the console.

The Sources tab of the Chrome developer console allows you to see the built code of your web app. It also lets you put in breakpoints to build the console and see the final file structure after the code has been compiled. We can see the built CSS and JavaScript files from here.

The Network tab is also an important tab of the Chrome developer console. It shows everything that’s uploaded and downloaded between your app and the server. All HTTP requests made by your app are shown here. When you click on an entry on the left side of the tab, you see the full details of the HTTP request made by your app.

Everything from the URL it’s making the request to, to the request and response headers of the request, and the parameters that were sent to the server are all shown here. Also, the status of the request is also seen here so if we can see if the request has been made successfully and the response code if the request has made it to the server. The Preview and Response tab on the right side shows the response body from the server.

It works for any kinds of responses. The Preview shows a formatted version of it while the Response tab shows the raw version. Finally, the Timing tab lets us see how long it takes to make a request between the client and the server. There’s also graph above showing the timing of the requests. You can filter them by different kinds of requests.

The most important ones for most web apps are the XHR tab for showing the AJAX requests only, and sometimes we also want to check JS, CSS, Img or Media tabs to see if the scripts and media are downloaded correctly. There’s also the WS tab for checking WebSockets communication.

The Network tab also lets us simulate different kinds of requests from normal requests to slow and fast mobile Internet and we can even cut off the Internet without pulling the wire or disconnect from our wireless Internet connection to see what happens when our browser is offline.

Chrome’s developer console’s Performance tab lets us profile the performance of our pages. We can check this tab of Chrome’s console for the loading time of various things like downloading scripts, rendering the page, and other things. This is useful for identifying performance bottlenecks with our code.

The Application tab of Chrome’s developer console is always very useful. We can see what’s stored in Local Storage, Session Storage and the cookies of our in here. Also, we can edit them and see the impact that it makes to our app. We can also clear all the storage of the current app loaded and start over without going to the browser settings to do so. This is handy for debugging any storage-related issues.

To audit the performance and accessibility of our app, we can go to the Audits tab of the console and toggle the settings to see what happens when we change different settings for simulating what kind of the device the web app is loaded in. We can change the bandwidth from slow mobile Internet to regular fast internet. Also, we can check if our progressive web app is actually compliant with the requirements of a progressive web app.

In addition, there’s also a responsive view to simulate how your page would look if you look at it from different mobile devices. It has a few phones and tablets to choose from by default.

As we can see the Chrome developer console is one of the best debugging and simulation tools out there. Other browsers like Firefox and Edge has similar functionality but might have different names. However, Chrome developer console is one of the most comprehensive front end developer tools out there. Other Chromium-based browsers should also have something like this.

Chrome Developer Console

Framework Specific Tools

If you’re writing apps with frameworks like React, Vue.js or Angular, then you should use the framework’s command-line tools to build your project. React’s too is called Create React App. Vue.js’s tool is called Vue CLI and Angular’s CLI tool is called the Angular CLI. All 3 frameworks have tools to start your project and build it into its final product. They also support for building them in different environments, so that you can put your environment variables in an .env file for the React Vue CLI. They can read from the environment variable files depending on the environment.

For Create React App, all your environment variable keys have to start with REACT_APP and for Vue CLI, they all have to start with VUE_APP. For building, they both can specify the environment that you can to build it in. For Angular, we can put the environment-specific variables in their own files and change angular.json to add the environment variables when you build. This is very handy since we don’t have to add extra tools to take care of this.

The Vue and Angular CLI can also run scripts to add code to add different things. For Angular, various libraries have provided an ng add command to add their own libraries in our apps. For example, NgRx store lets us run ng add @ngrx/store to add it to the app. And for Vue.js, various libraries like the Vue Electron Builder library which lets us build desktop apps with Vue.js provides us vue add electron-builder command to add their code to our own codebase. The library is located at https://github.com/nklayman/vue-cli-plugin-electron-builder.

Some command-line tools have their own specialized functionality. For example, Vue CLI can build code into web components with one command with vue-cli-service build --target wc --inline-vue . Angular CLI can create the different components in with one command like ng g component homePage to create a component called HomePage .

Finally, all the tools will build your apps for production use by minifying and obfuscating your code so that people can’t see the code in plain sight and that it’s as small as possible.

As we can see, using the command line tools that various frameworks is the way new front end apps are built now. It’s much better than creating the scaffolding of our apps manually, which is very tedious and error-prone.

JSFiddle

JSFiddle is a website that is great for fiddling with front end JavaScript code as the name suggests. It lets you quickly write front end HTML, CSS, and JavaScript code right on the home page. It also lets you add boilerplate code for the most popular libraries and frameworks like React, Vue, jQuery, and Bootstrap right on the home page. CSS preprocessors like SCSS are also supported and can be enabled with a click. You can see the output on the Result pane in the bottom right corner of the screen. This is great since it lets us make quick prototypes and snippets and save them if we make an account.

JSFiddle

JSBin

JSBin is another tool for fiddling with JavaScript code. It lets you enter HTML, CSS, and JavaScript and add popular libraries and frameworks like Angular, React, Vue, moment.js, jQuery, and many more. There’s also an output pane for seeing the results and with the Pro version we can have private snippets and Dropbox backups.

JSON Formatter and Validator

The JSON Formatter and Validator, located at https://jsonformatter.curiousconcept.com/, is handy for formatting JSON data into a human readable tree format. it’s great for visualizing JSON request and response data that we have to deal with often.

JSON Formatter

Mozilla Developer Network

The Mozilla Developer Network is one of the most comprehensive documentation websites for front end development. It has pretty everything we need to know about HTML, CSS, and JavaScript all on one website. It’s handy for knowing which APIs are compatible with which browsers. Also, it has a comprehensive functions that are included in each API. There are lots of new APIs in HTML5 so it’s one of the best go-to sites for looking up the APIs in a function. The full list of APIs spans many columns and each column is very tall, so there are lots of stuff, including experimental ones.

There’s also the References and Guides section for a long list of tutorials to learn all about front end development. It has everything from basic HTML, to animations, to basic back end development with frameworks like Django and Express. Also, it provides you with exercises and projects to do to learn the material that was covered. This actually has more complete than books that you pay for in the bookstore to learn about web development.

The URLs for the sections of the Mozilla Developer Network are the following:

Categories
JavaScript JavaScript Basics

How to Search and Replace Strings in JavaScript

Search

There are a few ways to search for strings in JavaScript. Strings has the startsWith , endsWith , indexOf , lastIndexOf , charAt , search and includes , and match functions.

startsWith

startsWith checks if a string starts with the substring you pass in.

For example:

const str = "Hello world.";  
const hasHello = str.startsWith("Hello"); // trueconst str2 = "Hello world.";  
const hasHello2 = str.startsWith("abc"); // false

endsWith

endsWith checks if a string ends with the substring you pass in.

For example:

const str = "Hello world.";  
const hasHello = str.endsWith("world."); // trueconst str2 = "Hello world.";  
const hasHello2 = str.endsWith("abc"); // false

indexOf

indexOf finds the index of the first occurrence of the substring. Returns -1 if not found.

For example:

const str = "Hello Hello.";  
const hasHello = str.indexOf("Hello"); // 0  
const hasHello2 = str.indexOf("abc"); // -1

lastIndexOf

lastIndexOf finds the index of the last occurrence of the substring. Returns -1 if not found.

For example:

const str = "Hello Hello.";  
const hasHello = str.lastIndexOf("Hello"); // 6  
const hasHello2 = str.lastIndexOf("abc"); // -1

charAt

charAt returns the character located at the index of the string.

For example:

const str = "Hello";  
const res = str.charAt(0); // 'H'

search

search get the position of the substring passed into the function. It returns -1 if the substring is not found in the string.

Example:

const str = "Hello";  
const res = str.search('H'); // 0

includes

includes checks if the substring passed in is in the string. Returns true if it is in the string, false otherwise.

const str = "Hello";  
const hasH = str.includes('H'); // true  
const hasW = str.includes('W'); // false

Replace

The replace() function included with strings are useful for replacing parts of strings with another. It returns a new string with the string after substring is replace.

Example:

const str = "Hello Bob";  
const res = str.replace("Bob", "James"); // 'Hello James'

replace() can also be used to replace all occurrences of a substring, for example:

const str = "There are 2 chickens in fridge. I will eat chickens today.";  
const res = str.replace(/chickens/g, "ducks"); // "There are 2 chickens in fridge. I will eat chickens today."

If the first argument is a regular expression which searches globally, then it will replace all occurrences of the substring.

Categories
JavaScript JavaScript Basics

Why Should We Use the JavaScript For-Of Loop?

Since ES6 we have the for...of loop. It’s a very useful loop that can do a lot more than regular for loops. In this article, we’ll look at why the for...of loop is useful for developers and whether the performance is good enough to replace the for loop.

The for...of loop lets us loop through arrays, array-like objects, and user-defined iterables. It lets us loop through all of them without using different kinds of methods and loops.

For example, we can create a for...of loop to loop through arrays as follows:

const arr = [1, 2, 3];

for (const a of arr) {  
  console.log(a);  
}

The loop will produce the following output:

1  
2  
3

Where the for...of loop shines is the ability to iterate through array-like objects like NodeLists and our own iterable objects. For example, if we have the following HTML:

<p>  
  foo  
</p>  
<p>  
  bar  
</p>  
<p>  
  baz  
</p>

then we can use the following JavaScript

const nodeList = document.querySelectorAll('p');

for (const element of nodeList) {  
  console.log(element.textContent.trim());  
}

Then we get the following logged:

foo  
bar  
baz

With the for...of loop we don’t have to write out the indexes like with a regular for loop to iterate through NodeList, which is the only alternative since it’s not an array, but an array-like object.

Also, we can iterate user-defined iterable objects like generators and iterable objects with it. For example, given the following generator:

function* generator() {  
  yield 1;  
  yield 2;  
  yield 3;  
}

We can use the for...of loop to loop through it as follows:

for (let a of generator()) {  
  console.log(a);  
}

Then we get:

1  
2  
3

Furthermore, we can define our own iterable object. As long as it has the Symbol.iterator method, we can loop through it with the for...of loop. Given that we have:

const iterableObj = {  
  *[Symbol.iterator]() {  
    yield 1;  
    yield 2;  
    yield 3;  
  }  
}

We can loop through it with:

for (let a of iterableObj) {  
  console.log(a);  
}

The for...of also has no problem looping through new objects like Set s and Map s:

const set = new Set([1, 1, 2, 2, 2, 3, 5, 4, 3]);

for (const value of set) {  
  console.log(value);  
}

Then we get:

1  
2  
3  
5  
4

Likewise, we can loop through maps:

const map = new Map([  
  ['a', 1],  
  ['b', 2],  
  ['c', 3]  
]);

for (const value of map) {  
  console.log(value);  
}

Also, we can loop through strings with it. For instance, given that we have the following string:

const str = 'foo';

We can loop through each character as follows:

for (let char of str) {  
  console.log(char);  
}

Then we get:

f  
o  
o

As we can see, it’s very useful for looping through anything that can be looped through.

Performance

We can test this by looping through a number array with 10000 entries. The array is constructed as follows:

let arr = [];  
for (let i = 1; i <= 10000; i++) {  
  arr.push(i);  
}

To test the performance of each loop, we use the console.time and console.timeEnd methods available in most modern browsers.

With the forEach method of an array, we get that it takes 840.8779296875ms to loop through each entry with the forEach method of an array.

With the for...of loop, it takes 843.972900390625ms to loop through each entry of the same array.

Finally, with a plain for loop, it takes 841.210205078125ms seconds to loop through 10000 numbers.

With length caching as we do below:

const len = arr.length;  
for (let i = 0; i < len; i++) {  
  console.log(arr[i]);  
}

It’s even faster at 593.16796875ms.

As we can see, the plain for loop is much faster. However, for looping through small amounts of data, we can live with the slightly slower performance. Also, we don’t have to write any extra code to loop through other kinds of iterable objects like Map s and Set s.

This means that for non-array iterable objects, the for...of loop is still better for looping through these kinds of things. Less code means less processing time is needed.

However, for arrays, if we loop through an array with lots of entries, then the plain old for loop is probably a better choice.

Should we use the for…of loop?

From what we looked at, the for...of loop is good for anything other than large arrays. It can loop through many more kinds of objects than other loops or the array’s forEach method out of the box.

It’s designed to be more flexible and clean than other loops.

Also, we don’t have to worry about what we loop through as long as they’re iterable, which isn’t the case with other loops.

The only thing that it’s not good at is looping through large arrays. In that case, use the for loop with the array length cached.