To start, make sure you're in the guide-1-react-router
folder in command-line.
# Install Node Modules
npm install
# Start the Server
gulp
# If you want to edit the react code, this rebuilds
gulp watch
The server will be available at localhost:3000
If you want to edit the React code, you'll have to re-build the public/js/bundle.js
file with Webpack. You'll probably want to open a new terminal tab so you can keep your server running. To rebuild with webpack, type:
gulp watch
Here are some details for this guide that weren't covered in the tutorial:
For simplicity, components in this guide are missing some formalities like prop types. I've tried to keep the components as simple as possible to get them working with the router. Since it's the minimal code to get the router working, the guide is missing many React best practices.
In the CodePen demo from the CSS-Tricks tutorial, we brought React and React Router into our application via CDNs. When a JavaScript tool is brought in through CDN, the tool globally available in the code, which is why the objects React
and ReactRouter
were available to us in the file. With bundlers like Webpack though, we are trying to avoid placing things in the global namespace. Each JavaScript module that we want to use (third-part or our own) will have to use include
statements to get access to it. This is why you'll see this at the top of most the files in the /app
folder:
include React from 'react'
Importing works similarly to CommonJS' require()
statement which automatically looks for our module (react
) inside of the node_modules
folder.
In the app.js
file (the entry file for our application), you'll see this code:
import Router from './router';
Since it's a relative path, the import
won't look inside node_modules
, but rather wherever our relative path points. The import statement is going to take whatever the /router.js
file wants to export, and it will place that content (usually an object) in our Router
variable. Then we can take the Router
variable and mount it to the DOM 'root'
:
ReactDOM.render(Router, document.getElementById('root'));
This may seen different from the CSS-Tricks article, but it's actually the same. If you look at what the /router.js
file is exporting, you'll see that it's a <Router>
. Just think of this as a way to organize our code so not everything is in the app.js
file.
Destructuring allows us to extract the intermal parts of an object into normal variables. So you may see lines of code like this:
import { Router, Route, browserHistory, IndexRoute } from 'react-router';
This is a combination of destructuring and imports. It's saying we want to import react-router
, but instead of getting the ReactRouter
object back, we want to extract certain properties from that object and create normal variables like Router
, Route
etc...
Here is a sample of the WidgetList
component. Notice it must import
React to work. Also notice that it's creating a constant called WidgetList
instead of using var
. As you read more about these new ES6 ways of creating "variables", you'll see that we should only use var
if we truly need something to be variable -- in other words, something that will change over time. In our case, the reference to WidgetList
(for this file) will always be the same thing and is not something that incurs variable change. Therefore it is a constant.
import React from 'react';
const WidgetList = React.createClass({
render: function() {
return (
<ul className="widget-list">
<li>Widget 1</li>
<li>Widget 2</li>
<li>Widget 3</li>
</ul>
);
}
});
export default WidgetList;
One of the more confusing parts about ES6 modules (to those familiar with require()
) is the word default
. With ES6 modules, each module can actually export more than one thing. Using default
means that this export
is the primary export of this file. It's more than just a formality though, using the default
syntax also makes importing easier. With the WidgetList
example from above, we are exporting WidgetList
by default. This means that when we import
WidgetList, we will get the exact same thing that was exported:
import WidgetList from './components/widget-list'
Had we not specified the default
and wrote the code as export WidgetList
, then the export would be an object with WidgetList
inside of it. That means the import
statement that receives it would have to look like this:
import SomeObject from './components/widget-list'
const WidgetList = SomeObject.WidgetList
I'm using "SomeObject" as a name just to show that it's obnoxious to receive the thing we want (
WidgetList
) wrapped in something else.
Or, we could use destructuring syntax like this to unwrap the WidgetList
into it's own variable:
import { WidgetList } from './components/widget-list'
With all these options, it's just easier to use the default
way.
If you look at all the components in Guide 1, you'll see that they all follow the same pattern of declaring a constant first, then exporting that constant as a default
. However, it should also be understood that we can export the component as a default
directly without creating a constant which does the exact same thing:
import React from 'react';
export default React.createClass({
render: function() {
return (
<ul className="widget-list">
<li>Widget 1</li>
<li>Widget 2</li>
<li>Widget 3</li>
</ul>
);
}
});
This just saves us some keystrokes, but as stated before, the examples use the other way with the constant because it might be easier for beginners to ES6 modules to grasp.