We've successfully created a working Application. When we run it, data is presented to the browser as intended. But what happens if we want to change the data? Currently, if we change the model, nothing. Lucky for you, React and MobX makes this simple.

Observable Properties

MobX provides Observable properties for objects. Once established, these special properties may be subscribed to. Then, if the value of the property changes, the subscribers will be notified with the updated value. These special properties can be read and written to exactly like regular properties.

We can use the TypeScript decorator @observable in the class definition to make a property observable.

@observable property: type = value;

Let's take our User example from the last chapter, and make it observable. So, simply import the @observable decorator, and add it in front of any properties you want to observe.

import { observable } from 'mobx';

export default class User {
    @observable firstName: string;
    @observable lastName: string;
}

And there we have it! Our firstName and lastName properties are now Observables!

Handling Input

Now that we can watch for changes in our data, let's set up some inputs!

import * as React from 'react';
import { observer } from 'mobx-react';

import User from '../../models/User';

export interface IUserViewProps {
    user: User;
}

@observer
export default class UserView extends React.Component<IUserViewProps, any> {
    render() {
        let {user} = this.props;
        return (
            <div>
                <p>First name: {user.firstName}</p>
                <p>Last name: {user.lastName}</p>
                <p>First name: <input type="text" value={user.firstName} /></p>
                <p>Last name: <input type="text" value={user.lastName} /></p>
            </div>
        );
    }
}

There are a couple of things to note:

  1. We have included observer decorator from mobx-react.
  2. We have used the @observer in front of our UserView to allow it to detect changes to Observables.
  3. We have included two <input> tags.
  4. We inject the value using {} notation.

When you run it, you will see your data now displayed in two text fields. But what happens when you type in the inputs? Currently, still nothing.

React works with one way data binding, meaning that changes to data flow from Application State to Components not the other way around. This is to prevent circular references, where an update moves from A to B to C and so on, but somehow goes back to A. If that happens, we will end up in an infinite loop.

So, any changes to our User will show up in our UserView, but changes to our UserView don't automatically go back to our User. In order for that to happen, we need to handle Events.

An Event is triggered when something happens, like when a user clicks the mouse, or presses a key. It can even happen when an AJAX call completes. Normally, a program will execute its instructions until there is nothing left to do, and it will either end, or wait for input. So, we need to handle that input.

For our UserView add these two methods above the render method.

updateFirstName = (event) => {
    this.props.user.firstName = event.target.value;
}

updateLastName = (event) => {
    this.props.user.lastName = event.target.value;
}

There are a couple of things to note:

  1. These methods will handle the Event, and store the value of the target into our User.
  2. We are using the Arrow Function notation, as the this value may be changed while executing.

But how do we hook these handlers up to our inputs?

<p>First name: <input type="text" value={user.firstName} onChange={this.updateFirstName} /></p>
<p>Last name: <input type="text" value={user.lastName} onChange={this.updateLastName} /></p>

And that's it! Any time the user updates the text inputs, the Event is triggered, and the User is updated.

We could also use regular methods instead of Arrow Functions for updateFirstName and updateLastName. In that case, when we inject them, we must use Function.bind().

<p>First name: <input type="text" value={user.firstName} onChange={this.updateFirstName.bind(this)} /></p>
<p>Last name: <input type="text" value={user.lastName} onChange={this.updateLastName.bind(this)} /></p>

In many cases, this syntax is harder to read, but it is personal preference. In some cases, where you must inject a specific value into the method, Function.bind(this, value) is useful.

Running our Application

So, we can now display and update our User. Try running it and see what happens!