Brian Holt -- worked at Netflix, Reddit, wrote Reddit's first React code
btholt.github.io/complete-intro-to-react-v1
nho.lt/react
Be above node 4 -- he's on 6+
nvm
is a useful tool
What is yarn? yarn
came out recently, it's new / shiny / fun, it replaces npm
, it's by facebook
npm install --save react
vs yarn add react
npm
installs are not "deterministic" -- they don't always endup in the same state
yarn
uses a lockfile, you always end up with the same dependencies
yarn
is faster
Note I was getting errors installing with yarn until I removed the npm install'd version and ran the following:
wget https://yarnpkg.com/install.sh
chmod +x install.sh
./install.sh --nightly
installing 800 dependencies in ~11 seconds
lots of alpha/beta versions, ignore the warnings
yarn installs all of your dependencies in a flat structure and "links" them together
NPM would build a giant tree with node modules -> node modules -> node modules etc
there's a yarn init
yarn upgrade-interactive
yarn global add _____
You don't need any tooling to write react
We will start with zero tooling
React is just a library with function calls that produces markup
No ES6, no JSX, just bare-bones react
Why is react useful?
If you're coming from jquery, angular, knockout, ember, etc...
React is "just a view library"
React is just the "view" in MVC
This is an over-simplification
MVC in the front-end?
Models / Views / Controllers
Backbone is where this started in the front-end
Models / Views in the front-end aren't quite "true"
Things get really blurry with what-goes-where
hard to debug/read
Angular / Ember focuses more on UI-type concerns
I have this piece of code that needs to do something
where does it go? This is still a thing.
This is a small problem while you write it, and a big problem when you need to debug
Where is the JS? Is it in the directive? Service? Scope / Template? etc.
React threw out "MVC"
Best pattern for UI -- request/response cycle
click a button, get a response, etc.
Squish together all the CSS/JS/HTML in a single "component"
By knowing what the problem is, we know where the code starts.
Don't mix libraries. If you're using React, go with React. Don't have a hybrid in production.
index.html
div w/ id="app" where react hooks to dom
text inside id="app" div will show until react renders
need to load both react/dist/react.js and react-dom/dist/react-dom.js
React is the library for expressing UIs
react-dom is the renderer
react-native, aframe-react, react3 are all renderers
we will be focusing on react-dom as our "glue layer"
Now we can write our JS -- let's just put it right in html for fun
React.createClass({ renderer: function() { return ( ... ) } });
You must have the parenthesis around your return value.
var MyTitle = React.createClass({
render: function() {
return (
React.DOM.div(null,
React.DOM.h1({style: {color: this.props.color}}, this.props.title)
)
)
}
})
var MyTitleFactory = React.createFactory(MyTitle)
var MyFirstComponent = React.createClass({
render: function() {
return (
React.DOM.div(null, // null is the attributes, classname / id / empty object / etc
MyTitleFactory({ color: 'peru', title: 'props are the best'}),
MyTitleFactory({ color: 'mediumaquamarine', title: 'strings'}),
MyTitleFactory({ color: 'blanchedalmond', title: 'and stuff'}),
MyTitleFactory({ color: 'rebeccapurple', title: 'are fun'})
)
)
}
})
ReactDOM.render(React.createElement(MyFirstComponent), document.getElementById('app'))
createClass vs createElement
createClass returns a "blueprint" that we can use to stamp out elements
createElement is one stamp
ReactDOM.render(React.createElement(MyFirstComponent), document.getElementById('app'))
Every component must have a render function
The render function must return markup
The render method must be a "pure" function
It should not modify any state
it should not have any lasting state
Every time you render it, you should get the same response as you did the first time
We won't be using semi-colons, and will be using standard
linter
var MyTitle = React.createClass({
render: function() {
return (
React.DOM.div(null,
React.DOM.h1(null, "Check out this component!")
)
)
}
});
var MyFirstComponent = React.createClass({
render: function() {
return (
React.DOM.div(null, // null is the attributes, classname / id / empty object / etc
React.createElement(MyTitle),
React.createElement(MyTitle),
React.createElement(MyTitle),
React.createElement(MyTitle)
)
)
}
});
ReactDOM.render(React.createElement(MyFirstComponent), document.getElementById('app'));
var MyTitleFactory = React.createFactory(MyTitle)
MyTitleFactory(null)
is now the same as React.createElement(MyTitle)
Now, we can do MyTitleFactory({ title: "Some prop"})
and pass in a title property, for example
Properties are read only
in our MyTitle
component, we can now do this.props.title
and get the value of the prop for the component
We can also pass in colors and use them as a style
styles are a little different
React.DOM.h1({styel: {color: this.props.color}}
var MyTitle = React.createClass({
render: function() {
return (
React.DOM.div(null,
React.DOM.h1({style: {color: this.props.color}}, this.props.title)
)
)
}
})
var MyTitleFactory = React.createFactory(MyTitle)
var MyFirstComponent = React.createClass({
render: function() {
return (
React.DOM.div(null, // null is the attributes, classname / id / empty object / etc
MyTitleFactory({ color: 'peru', title: 'props are the best'}),
MyTitleFactory({ color: 'mediumaquamarine', title: 'strings'}),
MyTitleFactory({ color: 'darkvioletred', title: 'and stuff'}),
MyTitleFactory({ color: 'rebecapurple', title: 'are fun'})
)
)
}
})
ReactDOM.render(React.createElement(MyFirstComponent), document.getElementById('app'))
non-configurable linter
prevents bike-shedding about JS style
outlaws semicolons (there's also semi-standard)
standard --fix
is pretty helpful
standard
is just wrapping eslint
with pre-set configuration
to make lots of the globals not be "undefined", we use /* global React ReactDOM */
easy way of running commands with lots of arguments
Just remember the name of the command and npm will do it for you
package.json
{
scripts: {
lint: "standard"
}
}
Not necessarily useful with standard
but much more useful with some of the more complicated build commands
gulp and grunt are still useful tools! Don't try to replace them entirely :)
Webpack is in beta only because its docs aren't done
Webpack is a great tool, takes all modules you create and puts it in one file to send-down to client
Also has "loaders" -- does lots of other stuff this way
We'll be using webpack2
this allows us to do things like import React from 'react'
-- es6 modules
also, export default Mytitle
CommonJS: var React = require('react');
We're not quite using webpack yet but will in a second.
/* ClientApp.js */
import React from 'react'
import ReactDOM from 'react-dom'
import MyTitle from './MyTitle'
var MyTitleFactory = React.createFactory(MyTitle)
var MyFirstComponent = React.createClass({
render: function () {
return (
React.DOM.div(null, // null is the attributes, classname / id / empty object / etc
MyTitleFactory({color: 'peru', title: 'props are the best'}),
MyTitleFactory({color: 'mediumaquamarine', title: 'strings'}),
MyTitleFactory({color: 'blanchedalmond', title: 'and stuff'}),
MyTitleFactory({color: 'rebeccapurple', title: 'are fun'})
)
)
}
})
ReactDOM.render(React.createElement(MyFirstComponent), document.getElementById('app'))
/* MyTitle.js */
import React from 'react'
var MyTitle = React.createClass({
render: function () {
return (
React.DOM.div(null,
React.DOM.h1({style: {color: this.props.color}}, this.props.title)
)
)
}
})
export default MyTitle
Need to install webpack first
sudo npm install -g [email protected]
webpack
webpack js/ClientApp.js public/bundle.js
This was what he suggested
I ended up using webpack js/ClientApp.js
which creates the bundle by default
this gives us the unminified, uncompressed version, not for production
NODE_ENV=production webpack -p js/ClientApp.js
will be much smaller
we want the debug version for develpoment to have better error messages
edit index.html:
just include public/bundle.js -- don't need to pull in other files
I had to add "propTypes" to my createClass, so it looks like as follows:
/* js/MyTitle.js */
import React from 'react'
var MyTitle = React.createClass({
propTypes: {
color: React.PropTypes.string.isRequired,
title: React.PropTypes.string.isRequired
},
render: function () {
return (
React.DOM.div(null,
React.DOM.h1({style: {color: this.props.color}}, this.props.title)
)
)
}
})
export default MyTitle