David Omotayo Frontend developer and indie game enthusiast.

How ArrowJS compares to React and Vue.js

9 min read 2596

How ArrowJS Compares To React And Vue.js

The frontend ecosystem is saturated with a plethora of frameworks, and it seems like new ones are being released daily. While many of these frameworks may not be as widely used as the more popular ones, some of them offer unique approaches that might pique your interest.

In this article, we will introduce ArrowJS, a JavaScript tool for building reactive user interfaces, and compare its approach to those of popular UI frameworks such as React and Vue.js. We’ll explore how ArrowJS differs from these conventional frameworks and what sets it apart.

Jump ahead:

Prerequisites

To understand the concepts and examples shared in this article, you should have the following:

  • Node.js installed on your system
  • Basic knowledge of JavaScript, Vue, and React

What is ArrowJS?

ArrowJS is an experimental tool for building reactive user interfaces using pure JavaScript. It uses modern JavaScript features, such as template literals, modules, and proxies, to implement its templating structure, observable data, and declarative/reactive DOM rendering capabilities.

The creator of ArrowJS believes it’s not necessary to have a complex framework to create impressive and performant user interfaces on the web because JavaScript has evolved to be powerful enough to handle these tasks natively.

As a result, ArrowJS has no dependencies, no Virtual DOM, no build tool, and no special templating language. It is also very lightweight, weighing less than 3kB (min+Gzip). This makes it ultra-fast compared to frameworks like React and Vue, which have comparable features.

Unlike many other JavaScript frameworks, ArrowJS does not use a build tool or a templating language. This means there is no need for compilation or conversion during build time, leading to better performance.

In contrast, React uses JSX as its templating language, which must be compiled and converted into native JavaScript render functions before it can be run in the browser.

Why use ArrowJS?

There are several reasons to consider using ArrowJS, including the following key benefits:

  • Build UIs with plain JavaScript: With ArrowJS, there’s no need to learn a new language or framework as you can use your existing JavaScript knowledge to create powerful user interfaces
  • Reactive programming model: With ArrowJS, your UI updates automatically whenever the underlying data changes, making it easy to build dynamic and responsive user interfaces that can react to changes in real time
  • Lightweight and easy to use: ArrowJS has a simple API and a small footprint, so you can add it to your projects without adding much extra code or complexity

We’ll dive into each of these benefits a little later in this article.

Getting started with ArrowJS

There are three possible ways to set up an ArrowJS application: using a package manager, installing locally, or via CDN. Let’s take a look at each option.

Installation from a package manager

As previously mentioned, ArrowJS does not include a build tool or bundler by default. However, if you want to use a package manager like npm or Yarn to bootstrap your project and take advantage of features like Hot Module Reloading, you can use a tool like Vite or Snowpack to bundle your project.

Use the following commands to install ArrowJS via npm or Yarn:

//npm 
npm install @arrow-js/core

//Yarn
yarn add @arrow-js/core

Installation from a local file system

To install ArrowJS locally, you’ll need to download the ArrowJS package from GitHub and add it to your project directly. Then, reference it in your script module like so:

<script type="module">
 import { reactive, html } from '/js/arrow.js';
 //your app’s code goes here
</script>

Installation from a CDN

Installing ArrowJS via CDN is as simple as adding the following import statement to your script:

<script type="module">
 import { reactive, html } from npm install @arrow-js/core'https://cdn.skypack.dev/@arrow-js/core';
 // Start your app here!
</script>

Understanding ArrowJS building blocks

ArrowJS is based on two composition expressions: static and reactive. However, the tool’s creator believes that reactivity should be an option, not a requirement. Therefore, ArrowJS is static by default and reactive by choice and only provides three functions for handling the templating and reactivity capabilities:

  • reactive (r)
  • watch (w)
  • html (t)

ArrowJS reactive function

The reactive function, or r in shorthand, is an ArrowJS function that converts generic data objects into observed data objects. This function monitors the object for changes and automatically updates any related templates or dependencies as needed.

Using the reactive function is straightforward; simply pass the object you want to monitor as an argument to the reactive function call, reactive(object), like so:

import { reactive } from '@arrow-js/core'

const users = reactive({
 name: “John”,
 age: 25
})

In this example, suppose we have a variable that depends on any of the object properties within the reactive data. When the object properties change, it is expected that the value of the dependent variable will be updated accordingly:

import { reactive } from '@arrow-js/core'

const users = reactive({
 name: "John",
 age: 25
})

users.name = "Mike"

const data = user.name;

console.log(data);

//logs 'Mike' to the console

However, ArrowJS offers $on and $off methods that allow us to observe changes to reactive properties.

The $on method takes in two arguments: the name of the property and a callback function. This method observes the specified property for changes and runs the callback function whenever a change occurs:

import { reactive } from "@arrow-js/core";

const users = reactive({
 name: "John",
 age: 25,
});

const nameFunc = (value) => {
 console.log(`name changed to ${value}`);
 const data = value;
 }

users.$on("name", nameFunc);

setTimeout(() => {
 users.name = "Mike";
}, 2000);

//"name changed to Mike" will get logged to the console two seconds after initialization

In the example above, the $on callback function will run when the name property changes.

The $off method, on the other hand, is used to remove the attached callback from the $on method.



For example, if we want to stop the reactive function from observing the name property, we would use the following code:

const users = reactive({
 name: "John",
 age: 25,
});

const nameFunc = (value) => {
 console.log(`name changed to ${value}`);
 const data = value;
};

users.$on("name", nameFunc);

setTimeout(() => {
 users.name = "Mike";
}, 2000);

users.$off("name", nameFunc);

//We stopped observing 'name' with $off
// so changing users.name will not log anything

ArrowJS watch function

Alternatively, we can use the ArrowJS watch function to track and untrack reactive properties. The watch function, w for short, is an inbuilt ArrowJS function, just like the reactive function. But, unlike the r function, watch takes in a function and tracks any reactive dependency of that function:

import { reactive, watch } from "@arrow-js/core";
 price: 25,
 tax: 10,
});

function total() {
 console.log(`Total: ${data.price + data.tax}`);
}

setTimeout(() => {
 data.price = 35;
}, 2000);

watch(total);

//"Total: 45" will be logged to the console two seconds after initialization

The watch function will monitor the price and tax reactive properties for any value changes. It also activates the $on observer for these properties and automatically detects when they are no longer being used by the function, at which point it will call the $off observer and stop tracking the property.

ArrowJS html function

The ArrowJS html function, t for short, is used for creating and mounting Arrow templates to the DOM. It uses tagged template literals to render contents declaratively.

To create an ArrowJS template, you prefix the tick mark with the html keyword or its shorthand t, and add the elements to be rendered.

For example, the keyword or its shorthand followed by an opening tick (html' or t') signals the start of the template, while a closing tick signals the end of the template.

We can then add the elements to be rendered within the ticks, like this: html`elements to be rendered` or t`elements to be rendered`

Here’s an example:

import { html } from '@arrow-js/core'

const appElement = document.getElementById('app');

const template = html`<p>Hello World</p>`

template(appElement)

In the above code, we’re referencing an element from the DOM and mounting our template to it.

Feature comparison

Let’s take a closer look at some of the features of ArrowJS and see how they compare to those of React and Vue.

Module structure and syntaxes

Unlike Vue, React, and most other JavaScript frameworks, ArrowJS does not use a component-based approach. Instead, it relies on functions. But since JavaScript components are essentially functions under the hood, both approaches are actually very similar.

These frameworks differ in the kind of templates they encapsulate and their overall structure. For instance, Vue uses a single-file component structure, in which a component’s template, logic, and styling are all contained within a single .vue file:

<template>
 <!-- html markup -->
</template>

<script>
 // JavaScript code
</script>

<style>
 /* CSS styles */
</style>

In contrast, ArrowJS uses standard JavaScript script modules and native code and functions:

import { r, t } from "@arrow-js/core";

const appElement = document.getElementById("app");

// JavaScript code
const user = r({});

const template = t`
 <div class="container">
 <!-- html markup -->
 </div>
`;

template(appElement);

At first glance, it may seem that ArrowJS is not very different from Vue, as both frameworks encapsulate their templates and logic within a single module. However, ArrowJS uses template literals (a native JavaScript feature) to interpolate expressions and directly render elements to the DOM. Meanwhile, Vue relies on the virtual DOM, an abstraction of the actual DOM.

Events

Another notable difference between ArrowJS and other frameworks is the syntax for binding event listeners to DOM elements. The tool uses the @ symbol, followed by an event name, to denote an event listener:

const clickHandler = () =>{
 console.log("clicked");
}

const template = t`
 <button @click="${clickHandler}">Click</button>
`;

This will automatically be translated to an equivalent expression:

document.getElementById("btn").addEventListener("click", () => {
 console.log("clicked");
});

In contrast, React and Vue use the camelCase naming convention and directives for events when binding event listeners to elements:

//React
const MyButton = () => {
 handleClick = () => {
 // do something when the button is clicked
 };

 return <button onClick={handleClick}>Click me</button>;
};
Vue
<template>
 <button v-on:click="handleClick">
 Click me
 </button>
</template>

<script>
 export default {
 methods: {
 handleClick() {
 // do something when the button is clicked
 }
 }
 }
</script>

Reactivity

Reactivity is a programming paradigm that allows us to adjust to change declaratively. This is merely a concept, not a default feature of programming languages. However, It can be implemented using different tools and technologies, depending on a given system’s specific requirements and constraints.

In JavaScript, reactivity can be implemented using frameworks and libraries such as React and Vue, which are designed for building reactive user interfaces. These frameworks use the virtual DOM to handle reactivity, updating it to reflect the latest data when there is a change. The framework then compares the virtual DOM with the real DOM to determine which parts of the UI need to be updated.

Given that ArrowJS uses native JavaScript, you may be curious about how it handles reactivity. The solution is a custom dependency class.

Reactivity in JavaScript can be implemented using a dependency class that takes in two properties: a value getter and a callback function. The value getter is a function that depends on multiple variables or dependencies to obtain its values.

Whenever the value of a dependency changes, JavaScript will automatically call the callback function and compare the current value to the previous value.

This is how ArrowJS uses the reactive and watch functions to handle reactivity under the hood. And, because ArrowJS doesn’t rely on mechanisms like the virtual DOM, its effects are instantaneous.

Another thing to consider is the conciseness of reactive implementation in ArrowJS compared to other frameworks. For instance, the code below demonstrates how to implement reactivity in a React component that shows a user’s name and age:

import { useState, useEffect } from 'react';

function ReactiveComponent() {
 // Create a state variable called "user" to hold the reactive data
 const [user, setUser] = useState({ name: 'John Doe', age: 32 });

 // Use the useEffect hook to specify a function that will be executed
 // whenever the user's data changes
 useEffect(() => {
 // Update the UI to reflect the latest user data
 // (e.g., update the name and age displayed on the screen)
 });

 // Return the JSX for the component, which includes the current
 // user's name and age
 return (
 <div>
 <p>Name: {user.name}</p>
 <p>Age: {user.age}</p>
 </div>
 );
}

Here’s the same implementation in ArrowJS:

import { r, html } from "@arrow-js/core";

const appElement = document.getElementById("app");

// Create a state variable called "user" to hold the reactive data
const user = r({ name: "John Doe", age: 32 });

 // Dom template which includes the current
 // user's name and age
const template = html`
 <div>
 <p>Name: ${user.name}</p>
 <p>Age: ${user.age}</p>
 </div>
`;

// Map template to Dom
template(appElement);

Declarative rendering

One aspect that these frameworks share is how they render declarative data properties in the template. React uses a placeholder indicated by single curly braces to insert reactive content and variables into the string, like so:

<div>
 <p>Name: {user.name}</p>
 <p>Age: {user.age}</p>
</div>

In contrast, Vue uses double curly braces, commonly known as the mustache syntax, to insert dynamic values into a string. For example, the above template would be rendered in Vue as follows:

<div>
 <p>Name: {{user.name}}</p>
 <p>Age: {{user.age}}</p>
</div>

Since ArrowJS uses native JavaScript to render elements, it has access to the special placeholder syntax provided by template literals. These placeholders, called template tags, are indicated using the ${} syntax and are used to insert dynamic values into the template at runtime. This allows ArrowJS to create templates that include dynamic data that gets updated whenever the data changes.

Template tags are used to insert the result of a JavaScript expression into the template. To create a template tag, you simply place an expression inside the ${} placeholder. When the string is evaluated, the expression is evaluated, and its value is inserted into the template in place of the placeholder:

const template = html`
 <div>
 <p>Name: ${user.name}</p>
 <p>Age: ${user.age}</p>
 </div>
`;

As you can see, the syntax for template tags is similar to that used in React and Vue, except for the $ symbol.

Template tags provide a simple and concise way to insert dynamic values into the template. These tags can be combined with other language features, such as arrow functions and destructuring, to create clear and easy-to-read code.

Conclusion

In this article, we introduced ArrowJS, discussed its many benefits, and compared its features to those of React and Vue. ArrowJS is still in an experimental stage, but is proving to be a powerful tool for building fast, reactive user interfaces with native JavaScript.

Building UIs with ArrowJS offers several advantages over traditional methods, including improved performance and easy integration with existing code. The use of native JavaScript makes ArrowJS a valuable addition to any developer’s toolkit.

Are you adding new JS libraries to improve performance or build new features? What if they’re doing the opposite?

There’s no doubt that frontends are getting more complex. As you add new JavaScript libraries and other dependencies to your app, you’ll need more visibility to ensure your users don’t run into unknown issues.

LogRocket is a frontend application monitoring solution that lets you replay JavaScript errors as if they happened in your own browser so you can react to bugs more effectively.

https://logrocket.com/signup/

LogRocket works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app’s performance, reporting metrics like client CPU load, client memory usage, and more.

Build confidently — .

David Omotayo Frontend developer and indie game enthusiast.

Leave a Reply