Making Vanilly App
Tags: javascript, webapp, vanilla
Published: 2019-08-05 15:52:28

---
title: Making Vanilly App
published: true
description: 
tags: js, webapp, vanilla
series: q23rp98u
---

It is great to be able to make app using Reaction, View, Angler. But it is cooler better if you can do even a small app with pure JS.

Today I will show you the way I did my vanilla app.

...

I call it "property-oriented pub-sub pattern". But before I will explain the idea, let's look at some essentials.

   Every app has three fundamental parts: State, Actions and Presentation layer. 
   **State** is an object with all changeable information.  Usually, every app has one global state and optionally little states for small parts of an app.
   **Actions** are functions, that change state. Usually triggered on some button press or on any other update.
   **Presentation layer** or "view", is a way to beautifully present the state to users.

   React+Redux cycle looks like this:
* trigger update of a state by pressing button (for example).
* basing on the new state we make new VDOM (JS-object as a representation of a future DOM).
* new VDOM compares with old one.
* basing on parts that was really changed, React updates only needed DOM elements.

![](https://thepracticaldev.s3.amazonaws.com/i/7p7wu2i5oufmusk7oaya.jpg)

propertyorientedpubsubpattern has much simpler flow. Action change a state and list all changed properties. Basing on changed state keys subscribed functions are triggered.

![](https://thepracticaldev.s3.amazonaws.com/i/s010l14x8e4sc5ysf9v4.jpg)

To make everything clear, let's first learn how to use it, then we will make it.

For example, we have a state "Character".
```javascript
const initialState = {
   name: 'Jake',
   age: 32,
   about: 'hi, im jake, yo',
}
```

We put it into some 'init' function, that gives us 'pub' and 'sub', to deal with.
```javascript
const {pub, sub} = init(initialState);
```
Then we make several components. 
```javascript
const c = document.createElement.bind(document); // alias for createElement
const q = document.querySelector.bind(document); // alias for querySelector
const Name = c('div');
const Age = c('div');
const MakeOlder = c('button');
MakeOlder.innerText = 'Make a person older!';
const App = c('div');
App.append(Name, Age, MakeOlder);
```
then use those pub-sub stuffs.
```javascript
sub(
   ['age'],
   age => Age.innerText = `age: ${age}`,
);
sub(
   ['name'],
   name => Name.innerText = `name: ${name}`,
);
const OLDER = pub(
   ['age'],
   state => ({...state, age: state.age + 1}),
);

MakeOlder.onclick = OLDER;
```
Now we have a little counter, masked as an account app.
As you can see, we explicitly list all properties public and subscribe to. When certain properties are updated, certain functions are triggered. Easy-Peasy.

So let's build this 'init' peace of function.

```javascript
const init = state => { // 1.
   const callbacks = {}; // 2.
   return {
      sub: (keys, fn) => { // 3.
         fn.args = keys; // 4.
         keys.forEach(key => {
            callback[key] = callback[key] || []; // 5.
            callbacks[key].push(fn);
         };
         fn(...fn.args.map(arg => state[arg])); // 6.
      },
      pub: (keys, update) => () => {
         initialState = update(initialState); // 7.
         keys.forEach(key => { // 8.
            (callback[key] || []).forEach(cb => { // 9.
               cb(...(cb.args || []).map(arg => state[arg]) // 10.
            });
         });
      }
   }
}
```
Now let me explain everything line by line.
1. state is kept in the closure.
2. 'callbacks' is an object, that holds all subscribed functions. Key is state property string, value - function, that depends on that key.
3. 'sub' takes keys of state, as you already know, and a function to trigger.
4. when function is subscribed on several keys, the function is listed in different arrays on several keys of 'callbacks' object. To save all keys associated with a function, we put them in 'args' property, cuz' functions are objects in JS.
5. if callbacks objects already has that key = we do nothing, otherwise we create empty array.
6. immediately call with arguments taken as keys from the state.
7. append the function to callbacks object.
8. we update the state by reassigning 'initialState' from closure.
9. for safety, if the are no array on that key, we use empty array(to do nothing).
10. same as at line (6.), trigger needed functions.

This code has list of defects, because i whated to make it as easy as possible, but it is already usable tool to make small apps!

If you what to play with this, here is codesandbox example:
{% codesandbox dhoev %}

Everything is great, but:
* some functions are can be called twice
* creating and updating elements via 'document' object directly is not cool
* we have no way to unsubscribe functions
* nature cataclysms are still happening

In the next episode we will fix some of those problems, so until next time!

lib: [repo](https://github.com/MikeSkoe/q23rp98u);
app: [repo](https://github.com/MikeSkoe/tasktimer)
[gh-pages version](https://mikeskoe.github.io/tasktimer/)