Posted on: 05/07/2018
This app is a mini demo for M-V-VM pattern and also a demonstration of my research on ReactJS. Please feel free to play with the app.
Before scrolling down to the details, you can take a look at the mini demo and the source code of the application at the links below:
This article will drive you step-by-step from creating a new React app to the deployment. However, the real deployment of React apps can be different depending on the 'NPM' libraries you would use in your app (ie. Node.js, Redux...). So this post assumes that you go with the default 'NPM' libraries.
Initial requirements:
NPM
installer: Download the latest version of npm and install it on your computer. You can follow this link to download.JSON
data: You should take some time to prepare a JSON
file(s) as sample data that will be used for your app.CSS
Framework: It's up to you to decide whether or not you want a CSS framework. Personally I would recommend Bootstrap as it's popular and easy to use. In my app, I use Semantic UI because I want to learn new things.My sample JSON data
[
{
"id": "100",
"title" : "Bujin Hirume",
"type": "Beast-Warrior / Effect",
"attack": 2000,
"defense": 1000,
"description" : "Cannot be Normal Summoned/Set. Must first be Special Summoned (from your hand) by banishing 1 \"Bujin\" monster from your Greaveyard, except \"Bujin Hirume\". If this card, which was Summoned this way, is destroyed by your opponent's card (by battle or by card effect), and sent from your side of the field to your Graveyard, and both players have a hand: you can discard 1 card, then your opponent discards 1 card. You can only control 1 \"Bujin Hirume\".",
"photo": "bujinhirume.png"
},
{
"id": "101",
"title" : "Bujin Mikazuchi",
"type": "Beast-Warrior / Effect",
"attack": 1900,
"defense": 1500,
"description" : "When a Beast-Warrior-Type \"Bujin\" monster(s) you control is destroyed by battle or by card effect and sent to the Graveyard: You can Special Summon this card from your hand. Once per turn, during the End Phase, if a \"Bujin\" monster(s) was sent from your hand to your Graveyard this turn while you controlled this face-up card: You can add 1 \"Bujin\" Spell/Trap Card from your Deck to your hand. You can only control 1 \"Bujin Mikazuchi\".",
"photo": "bujinmikazuchi.png"
}
]
Install NPM: The required packages and ReacctJS
After downloading the NPM
instraller, run the file and let the installation finish. Then you need to create a folder to host the required packages for React and initialize NPM
. Let assume you have created a folder named "reactApp" on drive C:\
. Now open the Command Prompt and run the following commands one by one:
// Initialize npm services
> cd C:\path\to\reactApp
> npm init
// Install babel plugin to compile and build the React app
> npm install -g babel
> npm install -g babel-cli
// Install webpack plugin as a vertual server to run your app on local computer
> npm install webpack@4.28.3 --save
> npm install webpack-dev-server@3.1.14 --save
// Now install react and update package.json file
> npm install react --save
> npm install react-dom --save
// Install other babel features for development
> npm install babel-core
> npm install babel-loader
> npm install babel-preset-react
> npm install babel-preset-es2015
// Create a folder of the first React project
> npm install -g create-react-app
> create-react-app your-app-name
Understand React project structure and mechanism
The last command will create a React project folder inside the "reactApp" folder. Then you can move your project folder to anywhere on your computer and use Visual Studio Code to open it. Take a look at the React project structure, first you should see the index.html
file. Notice the following line: <div id="root"></div>
Later in your development, everything will be dinamically rendered inside of this div
. In ReactJS, every element on a page can be a component, which is simply a Javascript class in your JS
or JSX
file. Let's navigate to src
folder and look at App.js
and index.js
files.
The index.js
imports the App component from App.js
file from React-DOM, then it injects this App component into the index.html
file, at the <div id="root"></div>
. The question is by how React-DOM knows the existance of the App component. To find the answer, look at App.js
file, notice the last line at the very end of the file: export default App;
The App component is exported to React-DOM at this line. Since you may export many components in one javascript file, the default
keyword signals a component is default and allows you to import those components in other files without using the brackets like import { component } from ...;
. Also in App.js
file, you see a method named render
with some HTML code in the return
statement. This render
method will be fired anytime a component is injected into a page, and the HTML code inside the return
statement will be placed somewhere on that page to display some useful contents.
Let say you have 2 components displaying on a single page (parent), let's call them Child1 and Child2. If you make some changes to Child1 in the source code, then only Child1 will be re-rendered on the page while Child2 remains still. So does Child2. And you will see the contents are updated without any browser or site reload.
Data Binding, Class Properties and State
To talk about data binding, pros and state, please open the Github link above to take a look at my React project. You need to see the file Content.js
at the following location: src/Content/Content.js
. Let me make it simple with the following shortenned version:
Now let's look at the file line by line:
JSON
content from a local file.props
) and status (state
). In the state
of this component, there is currently a JSON
array imported from local file. Whenever the contents of this JSON
array changes, the component's state will notify React-DOM to re-render the component automatically on the website.JSON
array to render every card into the page. The JSON
array is stored in mainDeck
variable. In React, we use method map
to iterate over an array because every element in the array will need to carry a unique key
after being rendered, so that React-DOM can identify whether a change has been ocurred to the state
and trigger a re-rendering. Apart from that, the key is also to ensure the elements not to be overlapsed or duplicated in the DOM after update.key={ card.id } card={ card } deck={ 'main' }
Whenever the data of a card has changed, the state of Content component will be notified (similar to the concept of Observer-Observable). The component will immediately send new data to and notify the Card component to update. Now the state of the Content component becomes the properties (props) of the Card component. The Card component is a Child of Content component, or Content component is the parent of Card component. To compare the props and state, the parent and child, there are some important things to note:
props
and state
both can be used for data binding. However, props
won't cause an update (if something changes) but state
will do (except when being controlled by component life-cycle callbacks).props
is advised to be immutable. That means we should never update props
with direct value assignment (ie. this.props.name = "Something"
). React will mess up and be unable to identify a re-rendering event. Instead we should use setSate
method (ie. this.setState({ name : "Something" });
).state
of a Child component is mutable only via its Parent component. So to update props
of a Child, we use setState
in the parent component to mutate the props
that are passing to the Child component. So React will propagate the changes to Child and update it, otherwise it will fail.onClick
, onChange
, onDrag
...).props
are usually passed over to state
inside the Constructor, so that we can keep props
not be mutated while allow the app to respond to changes.Method binding and passing
Back to the Content.js
, on lines 26 and 31, it is mandatory that we pass this
to the map
method on line 31. Keyword this
on line 31 refers to the component Content itself. This is another type of data binding inside a component. If we remove this
at line 31, React will have no idea of where the this
at line 26 comes from inside the render
method. So we need to bind method map
to the Content class to let it recognise the state
data of Content class.
On line 9 and 16, we have a function and we bind it to the component in the Constructor. This is one of the only 2 ways of binding that are considered good practice, since there is only 1 instance of the function is created and would be used for all instances of the Child component. On line 29, we pass the function to Child component just like the way we pass the component's state to its Child. Similarly the function passing this way will become a property (props) of the Child component. So when Child component invokes the function (ie. via user interactions), it is refering to the Parent's function.
The other way to properly bind function to a component could be as below. There are 3 other ways of binding but they may cause performance problems or throw warnings during compiling. So it's enough for you to only remenber these 2 binding methods.
Build and Deploy your app
With that much of knowledge, you can start your development at some basic steps at the moment. Finally to deploy your application, open Command Prompt and run:
> cd C:\path\to\your\app
> npm run build
The command will create a folder named "build" inside your project folder, then compile and build everything into "build" folder. You can upload that folder to the "public_html" on your server and enjoy!
It has come to the end of this post. If you'd like to perform further researches on ReactJS, here are some of the interesting resources: