Learn Vert.x And Build Ultra High Performance Servers With The Language You Want

Vert.x Provides Top Tier Performance and Allows You To Use Almost Any Major Language Out There

Connection network in dark servers data center room storage systems 3D rendering

Vert.x is one of the top performing server frameworks on Techempower. Most benchmarks have it within roughly 20% or less of the top performer, which is usually Rust Actix. Realistically that difference is nothing. It is also orders of magnitude faster than Node and Python related frameworks. On top of all this performance goodness, Vert.x is Polyglot. Since Vert.x uses the GraalVM runtime it supports the use of multiple languages including JavaScript, Kotlin, Scala, Java, Groovy, and Ruby.

If you prefer video learning

Where To Start

Let’s start at a high level in understanding Vert.x. Vert.x at its core is not a server framework. It’s more like a set of components for building event driven high performance applications. In other words Vert.x provides base level components that allow you to go off and build almost anything that requires very high performance. The main feature that allows this is the event loop (they also use the label Reactor Pattern).

If you’re a node developer you’ve probably already heard of the event loop concept. The event loop is an iteration looping mechanism that allows code to run asynchronously without using threads. In other words the system depends on callbacks instead of threads to scale. For programming old timers this may seem strange. But the reality is that threads do not scale. Although threads are generally tiny they still take up memory and require management by the operating system, not to mention having contention issues for shared memory. This ultimately limits their maximum scalability. You can see this is true because most thread based servers on Techempower don’t even make it to the top twenty.

So then why does asynchronous IO work better than threads. Because scalability for services is about simultaneous connections, more than CPU brute force. In other words it is an inherently IO bound activity. Threads on the other hand perform better for CPU bound activity. Note I’ll start writing vertx as the name to make it easier to type.

Verticle, The Core of Vert.x

So what else is there to know about Vert.x? Vertx at its core is made up of several sub components. Foremost is the verticle. A verticle is the minimum possible structure needed to create a vertx application. So you can think of it as a parent or container object, even though it’s possible to have more than one. All other components within a vertx application need to be initiated and setup from a verticle.

Inside every verticle is at least one event loop inside of a thread. Event loops live inside a thread because it is possible to have more than one event loop per verticle instance. Therefore having threads allows more cpu cores to be used to enhance scalability. There is an event loop thread pool from which verticle instances can get their event loops. As mentioned the event loop is the main “engine” that does the work of iterating in a loop. Each iteration will execute some action, for example accepting and then handling some request. Note the event loop itself is not inherently asynchronous. It’s only a mechanism to execute tasks in an iteration loop. So it is important not to have blocking code running in your event loop. There are several ways to avoid this which we’ll get into in a later article.

Next is something called the Context. The Context, as the name implies, is where data is shared within an event loop thread or worker thread. You can think of it as a simple session state for sharing data. According to the docs a context object is associated to a single event loop thread. Now because event loops exist inside a thread pool and can be shared among several vertx instances its not clear to me how constraining data to a specific set of services might work. I suppose you could simply add a prefix to your data keys to indicate some sort of grouping. But since the docs don’t comment I think this is a case specific implementation detail you’re going to need to work out. If you need to share data at a higher level, between verticles or vertx cluster nodes you can use the SharedData API.

EventBus, Vert.x Central Nervous System

In vertx it is possible to have multiple verticle instances. For example if you have a web server you might create a verticle handling http requests. Since a typical http server has numerous routes and some of them have complex handler logic it is possible that you might create a separate verticle for each route, both for logical structure and performance. Additionally, because vertx is Polyglot, you might write the http verticle in Java and some of the route handler verticles in JavaScript, in order to take advantage of language features or dependencies specific to that verticle business logic. So now you have multiple verticles that are distinct but need to communicate with each other. The EventBus allows this communication. It’s more complex than this simple explanation of course, and the docs say so as well, but I like to think of it as basically a pub/sub system for sending messages. By the way the default message passing format is JSON.

Simple Starter App

To get started let’s create a new project. One easy way to create a new project is to use the project creator on the vertx.io website. Go to the url https://start.vertx.io/ and select the following settings as displayed in the following.

Let’s take this project and open it with VSCode. Once you have downloaded it and opened it you should see a folder structure like this

Every vertx project will use a project and package manager. In our case we selected Maven. The pom.xml file will store our dependencies and list our basic configuration information for the app like the name and the main launching class name. In this case MainVerticle. We also selected Java as the main language, but in a later article I’ll show you how you can also create verticles using JavaScript.

Let’s start writing code. Open the file MainVerticle.java and add this code.

package com.example.starter;

import io.vertx.core.AbstractVerticle;
import io.vertx.core.Future;
import io.vertx.core.Promise;
import io.vertx.core.Vertx;

public class MainVerticle extends AbstractVerticle {

  @Override
  public void start(Promise<Void> start) throws Exception {
    
  } 
  
  public static void main(String[] args){ 
    Vertx.vertx().deployVerticle(new MainVerticle());
  }
}

As you can see a verticle must inherit from the base AbstractVerticle interface. Now normally you do not need to create a main method, because the pom.xml file is already telling the project which class to run on load. However if you want to use the VSCode debugger you do need this method as the debugger looks for it. So then let’s setup debugging for this project. Go to the debugger section and select the create launch configuration link. It will create a file for you and pre-populate it. Your’s should look like this.

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "type": "java",
            "name": "Debug (Launch)-MainVerticle<starter>",
            "request": "launch",
            "mainClass": "com.example.starter.MainVerticle",
            "projectName": "starter",
            "cwd": "${workspaceFolder}/src"
        }
    ]
}

Notice the cwd variable. Any source files should go there, like our MainVerticle.java, and also any config files should also go there. Now going back to the MainVerticle.java code if you look at the method main you will see that vertx is being instantiated there by calling deployVerticle and instantiating itself with new MainVerticle. Place a break point on that line and run the debugger we just created previously. It should break on that break point.

Now let’s update our start function and startup an http server. Add this code to MainVerticle.java

@Override
  public void start(Future<Void> startFuture) throws Exception {
    vertx.createHttpServer().requestHandler(req -> {
      req.response()
        .putHeader("content-type", "text/plain")
        .end("Hello from Vert.x!");
    }).listen(8888, http -> {
      if (http.succeeded()) {
        System.out.println("HTTP server started on port 8888");
      } 
    });
  }

If you run this code with the debugger it will go to the main method first and then run start. Start is the function that is supposed to initialize anything inside of your verticle. In this case we are enabling http services with the call to createHttpServer. However we could also use deployVerticle to create other verticles that are specialized to do specific tasks for our app. For example the route handling that I mentioned previously. Once you run this code you should see this on the terminal and browser.

In this article we covered the conceptual details of how Vert,x works and showed a simple example of how to get a base project started. In the next article I’ll show how to create route handlers for the http server. And how to deploy additional verticles.

More TypeScript Types You Need To Know … Better

You probably know at least some of these types already, but you might be surprised at some of the nuance of using them

Having static types in JavaScript is enormously valuable, but knowing how to use them appropriately can also be difficult. I think you might be surprised by some of the details of these types.

Null and Undefined Types Are More Than You Think

In JavaScript running typeof on null returns ‘object’. Some devs might have thought its type is null, since undefined’s type is undefined. Now to make things more confusing however, in TypeScript null’s type is null. Don’t believe me? Here’s a sample.

console.log(typeof null);
console.log(typeof undefined);
let val1: null = null;console.log(val1);
let val2: undefined = undefined;console.log(val2);

If you run this code you get this

So this detail is definitely something to be aware of when using these types. Here’s another question did you know that by default you can assign null and undefined to any object type? If this is not your experience it would be because your tsconfig.json file uses either strict: true or strictNullChecks: true. If you are using strict, which you should, then this behavior is not allowed without using a union. Here’s an example in non-strict and strict mode.

// non-strict this works
let val: number = undefined;// strict this works
let val: number | undefined = undefined;

Also note even if you have strict turned on null and undefined can still be set to an any variable, which does make sense. But is also another good reason not to use the any type.

Never Type

If you read my previous article on this topic, you’ve seen the any alternative called unknown. The never type is also a lesser known type. This type is a bit strange in that it attempts to describe the scenario where nothing is returned from a function, not even void. Huh? So then when can one return “never”. Here are some examples

function error(): never {     
    throw Error("failed!");
}
function neverFinish(): never {     
    while(true) {}
}

So now you’re like well that’s utterly useless. Actually not at all. Let’s give another example that’s a little more realistic.

function processSomeString(msg: string): string | never {    
    if(msg) {        
        // do some string work here        
        return "I finished processing your string.";    
    }    
    throw Error("no message given error!");
}
console.log(processSomeString(""));

If you run this code you will get an exception of course, but here’s the thing as TypeScript developers we know the value of static typing. It’s more than just having compiler help. It’s also about explicitness and communication. When we annotate with types we’re not just telling the compiler what we intend, but we’re also letting other devs know what we’re up to.

Therefore having something like never is an explicit way of giving other developers, not just the compiler, notice that something unusual could occur. To me I’ve always felt that functions that could throw an exception should indicate that in their signature. And using never is an easy clean way of doing that. In Swift programming you can indicate that a function can throw an exception in the function signature like this.

func canThrowErrors() throws -> String

I think both languages allowing for explicitness in communicating the possibility of unexpected situations is a very useful feature.


That’s it. Happy coding.

Here’s part one of this series.

As always if you like helping other devs try this DzHaven.com

OOP Is Still The Best Software Design Method Ever Created. Period.

Using OOP Language Features, Does Not Mean A Project Is Using OOP Correctly. The Principles Come First.

As a famous dude once said, “the rumors of my demise have been greatly exaggerated.” I think the same holds true for OOP. Developers are piling on in their disdain for OOP. OOP is a giant mistake! Paradigm X is better. So here’s a mixed list of facts and nonsense claims about OOP.

You Don’t Know OOP

When OOP is taught it usually starts with conceptual and abstract explanations. OOP is an extremely complex topic so starting with the technical details or code samples would be hard for anyone to digest. The problem is that since we are humans we can make all sorts of assumptions or draw incorrect conclusions based on high level explanations.

This is one of the most digestible technically accurate explanations of OOP I’ve ever seen, https://www.freecodecamp.org/news/object-oriented-programming-concepts-21bb035f7260/. I won’t even attempt to do it better because I cannot. Please review even if you think you know OOP.

The reason I’m suggesting you review it is because I recently watched a Youtuber video, with over a million views, and was surprised to see their explanation for Encapsulation. Basically this Youtuber explained Encapsulation’s main purpose as being the grouping of related object data. This is unfortunately not correct. Encapsulation’s main purpose is access control of member data. That is to hide member data so that it is strictly under the control of the class that it belongs to.

My point is this, there is a lot of incorrectly implemented OOP code out there, because developers misunderstand it. Just like there’s a lot of incorrectly implemented code in Functional Programming and just about any other major paradigm. OOP is an easy target because it is so ubiquitous, not because its bad.

Your Language Actually Does Not Do OOP

Let me lay it out flatly if you’re dissatisfied with the results of OOP, it may be that your chosen language does not really support it. Doh! I’ll say it another way if your language does not support static typing, access modifiers, and interfaces (or abstract classes), it can only mimic OOP and does not truly support it.

If you read through the link I had provided explaining OOP, you will see that without the core features I mentioned you simply cannot fully achieve most of the principles of OOP design. Some JavaScript people may believe that you can. For example it is possible to attain some Encapsulation, by embedding functions inside of constructor functions, to create member privacy and not expose them outside of the class. But so what? This is not a language feature, this is a work around for a missing feature that adds more code and more complexity. Developers have to know how to do it and other developers have to understand what this code means and so on. Is it a wonder that OOP is seen as too complex? But wait ECMAScript 2020 will soon allow for private fields. OK then what about more subtle access modifiers like protected and internal? I guess we can wait another 10 years for those.

For the other main principles of OOP it’s pretty much the same story. Abstraction requires a way to separate code interfaces from implementations. This is how we are able to dumb down a complex object so that we can hide its implementation and loosely couple our code. This is how dependency injection and true test mocking work. JavaScript and other dynamically typed languages again do not support interfaces or abstract classes. Sure it’s possible to simulate Abstraction. Maybe you use a facade pattern or adapter to mimic a reduced interface so that the internal complexity of an object can be hidden, but once again it’s not fluid and the direct language facilities are missing.

So then in the end what do you get? A lot of very clever complex code that may achieve some adherence to OOP principles but at what cost?

OOP Is Too Hard

My programming language supports OOP but it’s too hard. News flash programming is hard. It’s really really hard to do well. But that’s why we get paid the big bucks. Going to work every morning is hard. Working out is hard. But they all have their benefits when done properly. Trying to do anything well is hard. Don’t conflate poor OOP implementations with the idea that OOP sucks.

In my last job I would be the guy to interview candidates on their JavaScript skills. It always surprised me how many candidates had little understanding of some of the fundamental concepts of JavaScript. Prototypes, what this means under certain contexts, scoping rules (pre ES6), etc.

If you don’t know the tool you’re using you will use it poorly. This is just as true for programming paradigms as it is for languages.


There’s lots of different programming paradigms. For example I find Rust’s Trait based programming to be quite promising. It’s not at all OOP in my opinion. But having said that it has huge potential, both the language and the design style. As Rust develops further and more software is built using it, this style of programming may become the preferred way of coding large apps. However as of right now OOP is still king. It has the sophisticated tooling, the language support, and the developer mind share and experience. I suspect OOP will continue to be used for decades to come.

As always if you like helping other devs try DzHaven.com

TypeScript Types You Need To Know

If You’re Always Using Any For Ambiguous Situations You Are Doing It Wrong. There Are Better Safer Alternatives.


If you learn better with video try this

When you first start using TypeScript any situation where it is difficult to know the right type for a variable may cause you to set the type as any. Obviously this is not ideal as the whole point of using TypeScript is to have clear types set so that the compiler can help you catch errors — before your code makes it into production. Let’s see what methods there are already in the language that allow us to avoid using any and therefore gain the full benefits of using TypeScript.

Unknown Type

This is a type that I’m sure most TypeScript developers are aware of, but only a few are actually using. In addition there are some features of unknown that make it significantly different and safer to use than any. For example you might know that the unknown type allows setting of a variable to a value of any type. And that value can also be reset afterwards to a completely different type, just like the any type. However this is where the similarities end.

In the case of type any the compiler will not do type checking on your behalf. Once you set something to type any the compiler simply gives up and leaves you to your own devices. But in the case of the type unknown the compiler believes that your variable actually does have a type. However it does not know or even try and guess what that type is. It demands that you verify the type yourself and prove that it is of one type or another. Only then will the compiler allow you to either call into the variable’s members or set the variable to another variable of the same type (note without these checks it is still possible to set an unknown to another unknown or to an any). Let’s take a look at some examples of how unknown works.

First let’s look at a sample any variable.

As you can see I am able to set and then reset the variable val to a number and then to a string and an array. Now the most noteworthy part is that I am also able to call a function, myNonExistantFunction, that does not exist. This code compiles without error using the TypeScript compiler. However when you run this code, on the JavaScript output you get this error.

Clearly this sort of runtime failure could be avoided by using a proper type declaration. Unfortunately not every situation provides clear information on what the correct type of some variable or return should be. For example when calling a web service or accepting json data. The type information may not be clearly defined or not directly compatible. It may even change under certain circumstances. This is why the unknown type is so useful. Let’s look at the same example using unknown as the type.

As soon as you enter this code you should see your editor complain about the function myNonExistantFunction, that it does not exist for type unknown. But here’s the thing with unknown it will not allow you to call any members of a variable or set that variable to anything until you have proven that it is of the type required. So if I do this it also complains.

This may be unexpected, because clearly right above the line val.push() I set the val variable to a new array. So then how do I make use of a variable of type unknown? Let’s update the code so that adding to the array works.

So there’s two things to note here. First an unknown variable or return does have an actual type above and beyond unknown. So a simple way of thinking about it is that the type unknown is more like a label and “hidden” inside is the real type. Second once I’ve confirmed what type is actually being used only then can I call into the variable members or set it to some other variable of the same type.

So unknown is a good alternative to use instead of any in situations where it’s not immediately clear what type something should be or if that type could potentially change. However there is another way to deal with type ambiguity, union types.

Union Type

In the case of union types they can be used similarly to unknown types. However they are a little less flexible in that you must know up front all the possible types that may be returned by some call. Here’s an example to clarify.

In the above example the result of compiling and running this code is this.

As you can see the TypeScript compiler accepts all three distinct types without issue (note in JavaScript undefined and null are different types, undefined is its own type and null is an object type). And JavaScript runs this code to completion. So again this is another alternative to the type any that still allows you to maintain type safety.

Interface Type

If you’re a TypeScript developer you’re already familiar with this type. However you may not have yet used it for difficult typing situations. For example for a recent project on my app, DzHaven, I had to setup payments. And the payment provider returned an enormous object for one of its calls. It had several dozen properties and some of those properties in turn had their own properties. However I was only using a tiny subset of those members. Additionally the payment vendor was not using TypeScript so it was not always clear what type each field should be. It would have taken hours to figure this out, but the return on time investment would have been very small since as mentioned I only needed a few fields.

These kinds of situations can cause some developers to just set the object as type any and be done with it, but again there’s lots of issues with doing that. So what I did instead is defined my own interface with only a subset of the fields and just set the return type as that. Here’s a possible example of such a scenario to clarify what I mean.

If you compile and run this code you will see that it compiles and runs without error and returns this.

You may be wondering why it returns all the fields instead of just the ones that are part of the type declaration. This is because the compiler does not change the set data, it only checks for a type match (the fields of type MyData). So when console.log runs it returns the entire object’s members.


As TypeScript continues to grow in popularity type definition files will continue to fill in type information and reduce the amount of ambiguous typing scenarios we face. However until that happens completely, as TypeScript developers we need to be careful to use the language in a best practices sort of way.

Cool that was a small overview of the ways in which you can maintain type safety in your TypeScript code and use the language in the way it was intended. Happy coding.

As always if you like helping other devs try DzHaven.com

Is It Possible To Build A Mobile iOS And Android App Using Standard React And Web Technologies?

Yes. In a normal React web app you can access the camera, location services, the file system and more


Did you ever think how awesome it would be if you could keep coding with React and web technologies and somehow still get your apps onto the Apple App and Google Play stores with native functionality? You wouldn’t need to learn Swift or Kotlin. Nor would you have to build the same app multiple times. I am going to show you a simple seamless way to do this.

We are going to create a photo app that lets us take pictures, save it onto the device, and view later with information about where the image was taken. Let’s create a new project using create-react-app and call it reactmobile. Now just to be clear I’ve not tricked you into becoming a React Native or Flutter dev. This app will be entirely a React web app, using all the common web technologies you already know — like HTML/JSX and CSS. So when you build the app UI you will be using those technologies like you always do. However we will add a set of npm packages that will allow us to interface into native hardware, while still writing pure JavaScript only. Let’s get started.

First open up a command line or in VSCode open your terminal. Let’s add our packages.

npm i @capacitor/core @capacitor/cli

Capacitor is a library that allows any browser based web application to access hardware services on mobile devices. This means that we can keep writing our code not only using React, but also continuing to use url routing, through React Router, and other familiar React tools like Redux. That’s right, nothing changes in your workflow. The only difference is through Capacitor you now have access to device hardware and are able to create apps for the Apple App store and Google Play store.

Now that we’ve installed Capacitor we simply need to turn it on for the mobile platforms that we care about in our project. In the interests of time I’ll keep this story for iOS devices only, but Android works just as well. To enable Capacitor for iOS run these commands. Note when running init you’ll be prompted for an app name and id. You can use whatever you like since this is just a test.

npx cap init
npx cap add ios

So what we’ve done here is enable Capacitor in our project and created a folder that has all the iOS related files and assets. You will never need to touch these files, they are auto created for you by Capacitor and then copied to your Mac’s XCode when you’re ready to build your iOS project. Let’s make one small change before moving on. Open the file capacitor.config.json and update the webDir variable to be “build” instead of “www”. Since our React project saves its production build into the build folder we need to let Capacitor know this. Now I’ll show how to add camera capability. Open the App.js file and update it like this.

As you can see the @capacitor/core package is imported with some properties. The most important one, Plugins, is used to access the camera. We use a useCallback React hook to initialize the camera with some default configs onto a simple interface with just one button to trigger the camera. Let’s run this on our iOS device by running the Capacitor cli commands to move our code over to XCode.

npm run build // need to build our project successfully first
npx cap sync // need to sync the ios folder into our XCode project oncenpx cap copy ios // copies all our build files into XCode
npx cap open ios // opens XCode project

You might find the addition of these commands cumbersome, but realize what’s going on here. Since we are building a native app we need to compile our app into a native iOS binary. Obviously the only way to do this is with XCode. So that’s what these steps are for. Now run the project on your iOS device and since we have no UI, you will see only one button that says camera. If you click on it you will see the camera app that looks like this.

Sweet we now have a working camera with almost no effort. Now let’s save the photo onto the filesystem so we can view it later. Add this code into the App.js file.

You can see we are now using a useEffect that reacts when the photo object is changed. This photo object takes the immediately taken photo from the camera. Now the thing with photos is that whenever a picture is taken it is first saved into temp storage and may be deleted by the device at some point in the future. So we need to move it into a permanent app directory. This is where Capacitor’s filesystem API comes in to help us access the native filesystem and read and write files. So the next thing we do in the code is we first read the file from its temp location with readFile, then we write it with writeFile into a permanent directory, and once written we retrieve the final path and then convert that filesystem path into a url — so that we can pass it to the img tag’s src attribute later. Note we also updated the JSX for alignment. Before looking at the screen again, let’s add code to save these image file names into local storage so that we can retrieve the images and display them into a list.

There’s quite a bit of new code but the main thing to see is that we are using Capacitors Storage API to retrieve and set the local storage, the get and set methods, with the names of the photo files. Notice also I’m using moment to make the file name a little cleaner. The key thing to pay attention to in the code is that the convertFileSrc function is required to convert the file path from a system file path to a url. Or else img tags will not recognize the path and they will fail. Here’s what the screen now looks like.

You can see not only the last taken pic on top but a list of all previous pictures beneath the camera button. Awesome we created a React web app that works on mobile devices as a native app. Now let’s do one more thing and add locations for each image taken. Update your App file like this.

All we did was grab the Geolocation object from Plugins on line 19. Then we use that object in the function getCurrentPosition, which get’s the coordinates. Then we call that function later when building the array of photos and pass the latitude and longitude together with the file name starting at line 46. We then later add the file name and coordinates as labels onto our picture list. On the screen it looks like this. Note the prior images wont have coordinates since we hadn’t taken them at that time.

Let’s think about what just happened here. You took your existing React and web skills and created a native app. No Flutter, PhoneGap, Java, Kotlin, Swift, etc. No need to write the same code two or three times. No need to build a quasi web app using React Native and React Native Web … You’re welcome.

As always if you like helping other devs try DzHaven.com

Build Mobile iOS, Android, and Web Apps Using React and Ionic, Part IV

Write Once Run Anywhere Is Alive And Well In Modern JavaScript Development

This is Part IV in a series. You can find the previous Parts here III, III. In today’s story we will complete our second tab and list out our previously taken photos.

Layout In Ionic

Since this screen has more content let’s learn a bit more about layout in Ionic before continuing. If your page has multiple container elements and requires some strict rules around layout, the Ionic grid system is a built-in easy way of getting that layout. It is very similar to Bootstrap and uses grid, row, and column components for controlling your layout. The column system has up to 12 columns per screen and the columns resize based upon the size of the screen, again like Bootstrap. In addition, the columns have size tiers like small, medium, large, etc. which are based on minimum widths so up to and above a certain width that tier would apply. Note you can even have the grid system use more than 12 columns by changing the — ion-grid-columns CSS variable. There’s a lot more configurability to the grid system and more details can be found here. But for our purposes we’ll use it in a simple form within the new second tab.

You may be wondering if it’s worth it to use the Ionic grid system instead of something more established like Bootstrap or your own classes. However since the Ionic grid system is integrated with their other controls, including themes and styles, I would recommend using their system.

Let’s use this grid system in our new second tab. But first let’s create it without grids to see some of the issues grids solve. Start our second tab by creating a new page inside of the pages folder called Photos.tsx. For now create it as an empty functional component. Since we already know how to modify routes and tabs, based upon the last stories, I’ll just show you the updated App.tsx file that will display the new second tab called photos. This is what it should look like after adding Photos as the second tab. Quick note if you’re curios where the new photos icon comes from, all icons can be found and searched by going to Ionicons (the default icons for Ionic).

Now go back to the new Photos.tsx file and add this code.

If you reload the screen you will see that the text alignment is not centered and on desktop screens it starts all the way to the left.

Now let’s replace this with a grid layout so we can get automatic centering and resizing. Update the Photos.tsx file with this code.

After rebuilding you should see this for desktop screens.

The grid, along with its styling automatically centers itself across different devices. This is what it looks like on mobile devices.

Let’s review this code to understand how this centering is done. The IonGrid is the main container for grid items. The immediate child of an IonGrid must be an IonRow. And it is possible to have multiple IonRow components in an IonGrid. Inside the IonRow is an IonCol, which will contain all of our content. Now in the IonCol you can see we have a size property for medium sized screens, size-md, that we set to 6 columns. If we left it with this property alone, then this column would shift to the left as the total count needs to be 12. However since we also use the offset property, we are telling Ionic to offset this column by 3 from the left, which puts it in the horizontal middle of the screen. Let’s continue to the grid’s content. You’ll notice that the column has a CSS class “ion-text-center”, which centers the text in the IonText component. This is one of many styling and theme related shortcuts, for all Ionic components, that can be used to very quickly get desired styling effects, while maintaining adherence to the core theme. Particularly useful are the ion-padding and ion-margin CSS classes. These classes provide a theme consistent offset for your controls that’s easy to use and ensures the same spacing throughout the entire app. There are dozens of styles that can be used to adjust text, alignment, and spacing. You can see a complete list here.

Before continuing lets run the app on our iOS device or simulator. Normally you need to run Ionic build first and then the other commands that were mentioned in our previous stories, but here’s a faster shortcut.

ionic cap run ios

This single command will build, copy, and then open your XCode project. However note it does not do the sync piece. So if you’ve not done that you’ll need to do it just once, before running this command. Also note in order to sync, your Mac needs to have Cocoapods installed. Now let’s list out the photos we saved previously into the filesystem.

Bugs and Updates

The Ionic team has just released an update to their @ionic/react-hooks package and it now includes hooks for the Filesystem. So we’ll update our Camera code to use those hooks. We’ll also need to update that file as I had an infinite loop bug which was causing the code inside useEffect to run multiple times. My apologies for the issue. So let’s first update the hooks package. I had some trouble getting it to auto increase to version 0.0.6, which is the one with hooks. So I had to first update the package.json file with that version and then run below.

npm install @ionic/react-hooks

Once you do that the code in Camera.tsx should look like this.

Starting near the top, as you can see we import the filesystem hook and get useFilesystem. I’ve also created a lastWebPath state object to detect when a new picture has been taken and prevent the infinite looping issue. I’ve also forced the camera source to be CameraSource.Camera so the user will not have to choose which source object to use. Moving down to the bottom you’ll also notice that imageNames is gone now and imagePaths no longer references the photoUrl. This is because on the Photos.tsx page I am now only going to use the file name instead of the path; because converting the imagePaths from string to JSON and back was causing some issues in reading the file paths by the img tag.

Using Ionic Lifecycle Events

The Camera.tsx file is now updated and is using Capacitor to save the new picture names into local storage. Now within our Photos tab, we can use storage and filesystem hooks to retrieve the file paths and display the images into a list. Let’s update the Photos.tsx file like this.

As you can see we have a new hook called useIonViewWillEnter. This lifecycle hook is one of four event hooks that occur on all IonPage components. The others are useIonViewWillLeave, useIonViewDidEnter, and useIonViewDidLeave. Since we want our file data to arrive before the screen completes drawing, we are placing code to retrieve that data into the useIonViewWillEnter handler. Note the React class lifecycle events are still available, like componentDidMount and the others, but you should avoid them because according to Ionic documentation Ionic has taken over lifecycle control and so these events may not occur at the time you expect them to. Let’s continue. Within the useIonViewWillEnter hook we are using the storage and filesystem hooks to retrieve the file names we had saved earlier and get the photo’s path. In case you’ve not used it before, for await is a newer way of doing a for loop using async await. If there are async calls inside the for loop it will wait on that line before continuing. I added this call to make sure that by the time setPhotoItems is called the photos is fully populated with elements. Now once getUri gives us back the photo path we create some list items that we will later feed to a parent IonList component. These IonItems contain an IonAvatar for our image and an IonLabel for our image name. In addition since this is a native mobile app I thought it would look nicer if we could follow some mobile UI paradigms and so I am also using the IonItemSliding component. This component will allow the listed items to slide out to the left and reveal a Delete button. Let’s start the app again with this latest update.

ionic cap run ios

This is what you should see on your device when you slide an item out.

As you can see the IonItemSliding component also accepts an IonItemOptions component which takes the IonItemOption component that will ultimately handle the Delete button click. But before we add the handler for deletion, let’s add a click event handler to show a larger modal view of each image avatar that is clicked. Here’s the updated Photos.tsx file with the modal code and event handlers.

Near the top of the Photos functional component you’ll see we have several new state objects currentPhotoUrl, currentFileName, and showModal. These will be used by the IonModal component to display the appropriate information or to toggle the modal window. Now within the useIonViewWillEnter hook we’ve updated the IonItem component to include the attributes data-name and data-path and the onClick event handler. If you look at the onClickSelectPhoto handler you see that we are using those data attributes to set the state objects we created earlier and opening the modal. If you look all the way to the bottom of the Photos file you’ll see the IonModal and related elements. Notice I am using one of the CSS utility classes for alignment and I also have a stylesheet, Photos.css imported, which sets the — height CSS variable of the modal.

#img-modal {--height: 30em;}

Once the modal is opened it uses the properties of the IonItem to display the appropriate file name and photo. Here’s a look at the open modal.

Great now we’re almost done. Let’s create the delete button handler so that users can delete unwanted images. In your Photos.tsx file find the IonItemOption onClick event and replace the dummy function with the name onClickDelete. Let’s also give this component the data-name attribute and pass it the image.fileName. Now In order to create the onClickDelete function we’ll also need to refactor the code inside of useIonViewWillEnter as we need to use that code also in our onClickDelete function. Let me show you the completed code and I’ll go through it.

So as shown previously we are using local storage on the device in order to store our file names. The code that was retrieving our file names was initially in the useIonViewWillEnter hook. We have now moved it into a new function called setIonListItems. Now inside of onClickDelete we add some code that retrieves the list of file names, but then creates a new list that does not include the selected file to delete. This new file name list is then once again saved into local storage and then again our setIonListItems function is called which resets the IonItem list of files. Try it out yourself on your device.


That’s it a small but functional photo app that works across iOS, Android, and the Web! I’ve had good results with Ionic so I’m going to update my own application, DzHaven, to use Ionic so I can put it in the app store. I might write about it here as well. Here’s the updated code for this series, https://github.com/dharric/MyPhotos. I hope you try Ionic on your next project. Good luck.

Build Mobile iOS, Android, and Web Apps Using React and Ionic, Part III

Write Once Run Anywhere Is Alive And Well In Modern JavaScript Development

This image has an empty alt attribute; its file name is f29af-1b7uupxvb_hrtgfj6eqkleq.png

This is Part III in a series. Part II added camera functionality onto our app. Part I began by introducing Ionic and setting up our project. Next we’ll continue building out our app by learning about the storage API in Capacitor.

We left off in the previous story having created the camera screen and being able to display the last photo taken. Let’s improve the looks of the Camera screen by adding a Card. Open the Camera.tsx file from the previous project and find the beginning of the JSX return statement. In our current project it should be line 39. Let’s update the file with the following code.

As you can see the buttons now live inside an IonCard component. Inside this component are also the header and content components. Here’s a couple of things to note about components in Ionic. All Ionic components can have two kinds of properties: code properties and CSS properties (same thing as CSS variables). As the name implies code properties can be set within JSX as React props to change style or behavior. CSS properties are variables that have been created in order to change styling of a component. As mentioned previously Ionic components are an aggregation of Web Components and DOM elements. Therefore changing a CSS style on an Ionic component will not necessarily have the desired effect. Let’s see then how we can control styling of components within Ionic. In the Camera.tsx file there is a component called IonCardTitle. Let’s try changing its color to orange. First go to the theme folder and open the variables.css file. Add this style to the file.

ion-card-title {
--color: orange;
}

Run ionic serve and once the server finishes recompiling you should see that the font color of the component has changed to orange. I’ll clarify what’s happening here. The name of the Web Component is ion-card-title. This is the real name of the component in Stencil and IonCardTitle is the JSX name used only in React. Several CSS variables are associated to this component during its definition. One of those variables is — color. Therefore if we select the ion-card-title component, within our CSS file, and reset the — color property any ion-card-title component will have its color changed. Let’s erase that style and continue.

Now when we take a picture we should see a slightly nicer interface.

So changing only a trivial amount of code we already have a better looking screen. Now let’s save each picture’s name into local storage and move the pics into the app’s directory.

As mentioned in my previous story, Part II, access to native capabilities is given by Capacitor. So we will use Capacitor via Hooks to access local storage. Install the package below, if you did not last time.

npm i @ionic/react-hooks

This package acts as a wrapper to use hooks syntax to access Capacitor plugins. Now that’s installed, let’s modify the Camera.tsx file again to manage the taken image file. First let’s add moment to give us easier date and time formatting.

npm i moment

We’re using moment to dynamically create unique file names, so we have no name clashes when saving file paths later. If you’re not familiar with moment don’t worry as we only use the formatter. To clarify, the meaning of the format “MM-DD-YY-h-mm-ss” is month, day, year, hour, minute, and seconds. And we use that as our file name. Now replace the useEffect function with this code

When a photo is taken the photo immediately gets placed into temporary storage, which may be deleted at any time. Since we want to keep our pictures we need to move them into the app’s own directory, which is what we’re doing here. Filesystem.readFile takes the file from temp and grabs it. Then Filesystem.writeFile takes that file and writes it into the directory of the app. After that Filesystem.getUri gets a system file path for the image. Once that system file path is gotten we use Capacitor.convertFileSrc to change the path into a url style file path since the img tags that we are using cannot read file system paths. Let’s try this Filesystem code on an iPhone. You’ll have to run the following commands to get the updated code into XCode

ionic build
ionic cap copy ios
ionic cap sync ios
ionic cap open ios

Again these commands are needed because Ionic apps are pure web apps. So we use these command line tools to compile our web code and bring it into our native coding environment, in this case XCode, so that it can be converted into a native app. Now compile and restart the app on your iPhone and take a new picture. You should see the following in the XCode logs.

You can see the file name, the uri file system path, and a url path. Now let’s save our file name and path into local storage so that we can use it again to display in our second screen as a list. I’ve updated the Camera.tsx file and yours should now look like this.

Towards the top you should notice there is a new hook that’s imported, @ionic/react-hooks/storage. This sub directory gives us the useStorage hook, which will grant us the functions to save and get data from local storage. So we update the useEffect function again, and you can see we use get and set calls to retrieve and update our data. Note that this data is only of type string. Therefore if it’s complex data that we have, we need to put it in as JSON string. Once again save, build, and sync these code changes with XCode, with the commands I just showed above, and then let’s run our app again. If you take a picture and look at the log you should see the file’s name logged and an array with just this one file path. Then if you take another picture you should see the second name and then the array grow to two items. And finally let’s shutdown the app and start it up again to see if our data saves across app loads. Now go ahead and take another picture. This time the log should show the latest file name and then an updated paths array with three pictures in it, including the new file. Here’s what I got in my log from this test.

OK I’m going to end it here. In the next story we’ll develop the second tab which will list out thumbnails of our images and allow us to select each one in order to get a full size view. Here’s the updated code.

%d bloggers like this: