- We've come a long way! We've learned
- JavaScript Basics
- Browser & DOM
- API's and Async
- Application setup & Compilation
- At this point we have all the concepts we need
- Today, we learn about React!
- Open source view framework developed by Facebook
- React lets you define interfaces in JavaScript
- React can render anywhere to anything
- Simple, powerful, and composable
- React is not a web framework (not tied to html/css).
- React isn't a full fledged application framework
- React is not Flux or Redux
Everything in React is a component. Think of a component as custom html tag that renders its own interface and comes packaged with its own behavior (click events, etc)
When you render a React component, it renders to a virtual representation of the interface in memory. This is called the "Virtual DOM". React then uses any number of open source plugins to render the virtual DOM state to an interface like the real DOM, a canvas, or a native mobile app.
The library we'll be using to render React components to an HTML document is called reactDOM. ReactDOM converts your React state to HTML. It manages the HTML and event handlers for you so that subsequent renderings of your application make the fewest possible changes to the actual DOM, increasing performance.
Important - React abstracts away the DOM interface. You're not really writing HTML.
Most React code is written in a superset of JavaScript called JSX. It lets you create components in your JS code in a way that looks more familiar (like HTML). Keep in mind, this IS NOT HTML. It's also not really JS. It needs to be compiled by webpack into a .js file that a browser can read.
Let's define our first component.
import React from 'react';
import ReactDOM from 'react-dom';
class HelloMessage extends React.Component {
render() {
return (
<div>Hello World</div>
);
}
}
var mountPoint = document.querySelector('#app');
ReactDOM.render(<HelloMessage/>, mountPoint);A few things to note:
- We are importing React and ReactDOM separately.
- We are using ES6 class syntax to define a new component class that inherits from React's default component
- We are defining a
rendermethod, which is the only method required to define a component class. - The render method returns a React component. Use parens to allow multi-line component definitions, and make sure you're returning a single root component. The root component can have children, but not siblings.
- We are using ReactDOM to render an instance of our class to an element on the html document.
Like we said before, JSX isn't really HTML. Because it lives in the same context as JavaScript, it has some special rules you need to follow when returning components from your render method.
- Attributes with the same names as reserved JS keywords can't be used. For example
classandforare changed toclassNameandhtmlForin JSX. - All tags have to be closed.
<input type="text">for example, has to include a closing tag<input type="text" />.
Let's create our first component!
- Clone the boilerplate project from
git@github.com:ttsJavaScriptApps/webpack-boilerplate.git - In index.jsx, create a component class called
MessageInputthat renders:- A text input called
- A label for the text input (clicking it should focus the input)
- A 'send' button
- Render an instance of your component to the DOM.
Let's take a deeper look at the render method. This is essentially the equivalant of our view template in other frameworks (ejs, handlebars, mustache, jade, haml, etc.).
The basic functionality needed in any templating language is
- Token Replacement
- Conditions
- Iteration
Let's take a look at how we do that in JSX.
Before we make our templates dynamic we need data to drive them. The data that components need to render is kept in a special property object called state.
We add a constructor method to define our component's state object.
class HelloMessage extends React.Component {
constructor() {
super(); //needed for inheritance
//Define an intial state object
this.state = {
message : 'Hello World'
};
}
render() {
return (
<div>Hello World</div>
);
}
}Now that we have data, we can start making our templates dynamic.
Token replacement is simply taking variables and putting their value into the template. In JSX, use curly braces with a variable name:
// this.state = { message : 'Hello World'};
render() {
return (
<div>{this.state.message}</div>
);
}Tokens don't have to come exlusively from state. They can be calculated. e.g.
render() {
var statement = "message is: " + this.state.message;
return (
<div>{statement}</div>
);
}Often times we want to render one thing in one case, and something else in another case. There are a couple of ways to do this with JSX
// this.state = { person : 'Matt'};
render() {
//Figure out the elements in advance
if(this.state.person)
message = "Hello " + this.state.person;
else
message = "I'm all alone... and sad";
return (
<div>{message}</div>
);
}If you prefer an inline look to your template, remember, you can run functions inside those curly braces. Use an IIFE to generate the value you want
render() {
return (
<div>
{(() => {
if(person)
return "Hello " + this.state.person;
else
return "I'm all alone... and sad";
})()}
</div>
);
}Sometimes you want to render the same elements repeatedly for every item in an array. JSX lets you put an array of components inside the {} for rendering. All you have to do is create it based on the data you want to render.
//this.state = { studentNames: ['Matt', 'Katy', 'Mariel', 'Lee'] }
render() {
//Figure out the elements in advance
var students = this.state.studentNames.map(function(name){
return (<li key="name">{name}</li>)
})
return (
<ul>{students}</ul>
);
}Something to note above is the use of the key property. In order for React to keep track of and property update dynamically generated elements, give them a unique "key". Above, we're using the student name, which isn't guaranteed to be unique, so be careful choosing your key.
One of the most common dynamic elements is the list of classes an element has applied. The simple way to do this is to use javascript logic to concat a string.
//this.state = {active: true}
render() {
var classes = 'item'
if(isActive) {
classes += 'active';
}
return (
<div className={classes}></div>
);
}A better approach is to use the 'classnames' module
import classNames from 'classnames';
render() {
var classes = classNames({
'item' : true,
'active' : isActive
})
return (
<div className={classes}></div>
);
}Because React brings HTML, CSS, and JS into the same context, you can use POJOs(Plain ol' JavaScript Objects) as styles for your components!
render() {
var headerStyle = {
color: 'red',
textDecoration: 'underline'
}
return (
<h1 style={headerStyle}></h1>
);
}You can define styles in another module and import them.
Let's add some logic to our little component.
- Declare an array of message objects with properties for
text,time, anduser - Add a
ulwith anlielement for each message containing the message, user's name and timestamp. - Declare a variable
currentUserand set it to one of the users in the messages array - If a message's author is the
currentUser, add a class to it that turns the message red. - Only show the most recent 3 messages.
- If there are more than 3 messages, show a "load more" button
-
Start Reading the React Documentation
-
Complete the first 3 challenges (stop at Step 2 - Part 3) of Thinking in React module
-
https://www.nczonline.net/blog/2016/01/react-and-the-economics-of-dynamic-web-interfaces/