In this tutorial, we take a look at React and MobX, what they can do, and the fundamental parts of any React and MobX project. You should already have a TypeScript environment running, and have included the necessary packages in your project dependencies.
Project Organization
Any React and MobX project includes Application State and Components. This is similar to many common patterns such as MVC or MVVM, where you have a distinct separation between your data, and how you display it. Ultimately, the specifics of your pattern are up to you, but the overal concept is the same. We will introduce some common patterns in later tutorials.
Before we get started, your TypeScript project should have a tsconfig.json
file. Open this file, and ensure the following options are set:
"jsx": "react",
"experimentalDecorators": true,
"lib": [
"dom",
"es6"
]
Also, ensure that you have src
and public
directories in your project.
Building your Project
It will be easier to develop our project if we can run it. Let's start by setting up a simple set of files and getting the to build.
Inside the public
directory, create a file index.html
. This will be the main HTML file that runs the project.
<!DOCTYPE>
<html>
<head>
<title>Tutorial 0</title>
</head>
<body>
<div id="root"></div>
<script src="../../dist/bundle/main.js" type="text/javascript"></script>
</body>
</html>
This file creates a <div>
to mount our component, and then loads the script. Note that we're loading our script from bundle/main.js
, which is a file that doesn't currently exist. We are going to build it later.
Inside the src/scripts
directory, create a file main.tsx
.
window.onload = function () {
console.log('started');
}
We now must set up Webpack to build our main.tsx
file. Inside the webpack configs (there are two if you're using the ts-boilerplate), ensure that the entry
and output
objects have the correct values. it should read:
entry: {
'main': './src/scripts/main.tsx'
},
output: {
filename: './public/bundle/[name].js',
libraryTarget: 'var',
library: '[name]'
},
This is likely very similar to what is already there. Simply change main.ts
to main.tsx
, the filename from dist
to public
, and remove the .min
portion of the filename.
Now to test it, run
npm run dev
If you want to run automatically as you're developing, call
npm run watch
If you want to run a minified version of the file, call
npm run min
If it is successful, open the public/index.html
file in your browser. Open the browser's console (F12 on Windows, Ctrl+Shift+J on Windows and Linux, or Cmd+Opt+J on Mac), and you should see started
printed to the screen.
Also, if you are using the ts-boilerplate code, clear the tests out of test.ts
. This will prevent breaking any irrelevant tests.
Application State
MobX stores its data in Application State objects. Depending on what you want to store, they may contain values, other objects, arrays, or even methods to manipulate the data.
Let's say we want to create a Model of a User. It should store common information for our users, like first and last name. We also will want to edit it.
So, we start by declaring a class, and adding several properties. Inside your project, create a folder src/scripts/models
, and inside it a file User.ts
.
export default class User {
firstName: string;
lastName: string;
}
Fantastic! We now have a User class which will correctly store our data! We have also exported it as default from this file.
Components
React displays its data in Components, which are simply classes that render to the DOM. They may render Nodes, strings, numbers, nothing, or even other Components.
So, since we have our User model, let's display it! Inside your project, create a folder src/scripts/views
, and inside it a file UserView.tsx
.
First, we must import React into the file.
import * as React from 'react';
We have imported React, which contains the Component class. While we will not necessarily use the React
import directly in our code, the JSX interpreter will transpile our JSX statements into React calls. This process turns what appear to be XML elements into:
React.createElement<P extends DOMAttributes<T>, T extends Element>(
type: string,
props?: ClassAttributes<T> & P,
...children: ReactNode[]): DOMElement<P, T>;
Now we must import our User model.
import User from '../models/User';
We now must define what properties our component takes. Our component will take in a user. These appear as XML Attributes in our JSX code.
export interface IUserViewProps {
user: User;
}
Next we need to define our component itself.
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>
</div>
);
}
}
This component takes in a user, and displays the firstName
and lastName
inside to <p>
elements, wrapped inside one <div>
element.
There are a couple things to note:
- We used the Props interface inside the Component definition. This provides intellisense both when writing the component, and later when we use it.
- We used object destructuring to get
user
fromthis.props
. This is a shorthand that is much simpler thanlet user = this.props.user;
. It especially comes in handy if you're doing that for multiple properties. - Every component must define a render method, even if it returns nothing.
- A component may return exactly one value. Here we wrapped our multiple
<p>
tags in a single<div>
tag. - We user the
{}
notation to insert theuser
values into the elements.
Rendering
We now must render our Application State into Component and display it to the DOM.
Inside the main.tsx
we must import all of our files, and then render them.
import * as React from 'react';
import * as ReactDom from 'react-dom';
import User from './models/User';
import UserView from './views/UserView';
window.onload = function () {
var user = new User();
user.firstName = 'First';
user.lastName = 'Last';
ReactDom.render(
<UserView user={user} />,
document.getElementById('root')
);
};
There are a couple things to note:
- We imported ReactDom, our
User
, and ourUserView
. - We write our code inside the onload function to ensure it runs after everything is ready.
- We create a new user and set the first and last name properties.
- We get the
root
element from the DOM - We create a new
UserView
with JSX, pass in the user. - We pass the
root
element and theUserView
toReactDom.render()
.
Now build the project and run the HTML file in your browser. It should display your user in the HTML you specified.