Mint 🍃: Events and State of Components
Tags: mintlang, javascript, frontend, webdev
Published: 2019-04-26 13:35:35

_This the third post in a series that showcases the features of Mint, you can find the previous posts here:_
* _[Mint 🍃: Getting Started](/gdotdesign/getting-started-with-mint-3k2o)_
* _[Mint 🍃: Components](/gdotdesign/components-in-mint-4a4n)_

In this post I will show you how to use **events** and the **internal state** of components :)

## Events

Every web application leverages events to handle change in it's state, such events can come from a couple of different sources:
* user interaction from DOM nodes
* interactions from the browser itself
* interactions from a server (for example from a WebSocket connection)
* and possibly other sources

I will show you how to handle events that come from DOM nodes.

### Event attributes and handlers

As in React, DOM nodes can have event attributes attached to them: every attribute which starts with **on** is an **event attribute** (`onClick`, `onMouseOver`, etc...)

_Since Mint uses React as platform you can refer to its documentation on the list of [supported events](https://reactjs.org/docs/events.html)._

Event attributes values are **functions** which must match one of the following two types: 
* `Function(a)` which returns `a`
* `Function(Html.Event,a)` which takes an `Html.Event` and returns `a`.

_`a` is a type variable which means it can be any other type._

For example both handlers are valid in this example:

```
component Main {
  fun increment (event : Html.Event) : String {
    Debug.log("Increment")
  }

  fun decrement : String {
    Debug.log("Decrement")
  }

  fun render : Html {
    <div>
      <button onClick={decrement}>
        "Decrement"
      </button>

      <button onClick={increment}>
        "Increment"
      </button>
    </div>
  }
}
```

When clicking on a button you will see `increment` or `decrement` in the console depending on which button you clicked.

_As you can see you can reference the function itself without calling it, just by its name._

### Html.Event

The `Html.Event` type is a normalized version of the [DOM Event](https://developer.mozilla.org/en-US/docs/Web/API/Event) interface, you can see the actual type definition [here](https://github.com/mint-lang/mint/blob/master/core/source/Html.Event.mint#L2).

## Internal State

Components can have their own state to achieve some specific functionality which does not require a global state.

A **state** can be defined using the `state` keyword similarly to the `property` keyword:

```
component Main {
  state count : Number = 0

  ...
}
```

This **state** can be used across the component just by referencing it:

```
  ...
      <button onClick={decrement}>
        "Decrement"
      </button>

      <{ Number.toString(count) }>
      
      <button onClick={increment}>
        "Increment"
      </button>
  ....
```

### Modifying State

A state (or multiple ones) can be set using the `next` keyword: it tells the component to replace the given states with new values.

_States don't mutate but get replaced because data-structures in Mint are immutable._

For example we modify our functions to update the count:

```
...
  fun increment : Promise(Never, Void) {
    next { count = count + 1 }
  }

  fun decrement : Promise(Never, Void) {
    next { count = count - 1 }
  }
...
```

Notice that the return type of the function has changed to `Promise(Never, Void)`. 

Promises are used in asynchronous computations (which we will touch in the next post) and modifying state returns a promise because it is considered a side-effect.

A promise has two parameters, the first is the error type in this case it's `Never` to indicate it can't fail and the second is the type of the return value when it resolves, in this case it's `Void` meaning its not relevant (basically cannot be used for anything).

--------------

Here is the full source, thank you for reading 🙏:

```
component Main {
  state count : Number = 0

  fun increment : Promise(Never, Void) {
    next { count = count + 1 }
  }

  fun decrement : Promise(Never, Void) {
    next { count = count - 1 }
  }

  fun render : Html {
    <div>
      <button onClick={decrement}>
        "Decrement"
      </button>

      <{ Number.toString(count) }>
      
      <button onClick={increment}>
        "Increment"
      </button>
    </div>
  }
}
```

--------------
If you like to learn more about Mint check out the [guide](https://guide.mint-lang.com) 📖

In the next part I'm going to show [how to load and display data from a JSON API](https://dev.to/gdotdesign/mint-handling-http-requests-2ep3) 😉 see you there 👋