Вы находитесь на странице: 1из 13

Introduction to React.

js
Learn the basics of React, one of the most
popular JavaScript frameworks out there. It's
used by companies large and small including
Instagram, Netflix, Airbnb and many more!
Why React.js?

React, to quote Facebook themselves, was built to solve one problem:


building large applications with data that changes over time. (thats why
Instagram and Facebook are built with it)

With React, its simple to express how your app should look at any given
point in time. It will figure out which parts need to update when the data
changes for you, and will only render those.

It also popularised building apps with encapsulated, reusable and


composable components. Its a different way of thinking and of going
about building webapps, but once youre used to it you can never go
back!

What well build

This is the app well be building in this tutorial series (yes, this is a live
example! Click around and explore):

You can also see this example in your own browser at


blog.mxstbr.com/weather-app

In this first chapter of the tutorial well go through the React basics,
before starting to build the above app in chapter two. If you feel
comfortable with React and JSX feel free to skip ahead but I highly
recommend going through this chapter to make sure you know React!

Getting Started
Well use react.jsbin.com for the initial explanation, which has a fully
featured React environment set up. With this, you can quickly experiment
and get a feel for React.

React consists of two libraries, React and ReactDOM. React allows you to
create elements, which we render with ReactDOM. They are split because
you could (theoretically) render those ReactElements anywhere, not only
to the browser DOM.

For example, there are initial experiments out there for rendering React
to Canvas, WebVR and even hardware!

Open up our first JSBin, and you will see an <h1> with the text Hello
World. This is the source code generating that text:

ReactDOM.render(
React.createElement('h1', {className: 'heading'}, 'Hello World'),
document.getElementById('container')
);

We use the ReactDOM.render() function to render a ReactElement created


with the React.createElement() function.

ReactDOM.render()

The ReactDOM.render() function takes two arguments: The ReactElement


to render, and the DOM node we want to render into. (the entry point)

ReactDOM.render(
React.createElement('h1', {className: 'heading'}, 'Hello World'),
document.getElementById('container')
);

Now you might think creating a ReactDOM.render() function for every


ReactElement you have is the way to go. Thats not a very good idea it
empties the DOM node we use as an entry point. How do we render
multiple ReactElements then? Lets take a look at the
React.createElement() function to figure it out!

React.createElement()

This function takes the node (or ReactElement) we want to create as the
first argument and some properties (like type) in an object as the second
argument:

React.createElement('input');

React.createElement('input', { type: 'radio' });

React.createElement('input', { className: 'heading', type: 'radio' });

Notice how the HTML class attribute has to be set via className
property in react. This is because class is a reserved keyword in
JavaScript, which means we might introduce unwanted problems into
our apps by passing in class. React mitigates this by using the
className property instead of class!

We can also (optionally) pass children as the third argument! The simplest
usecase here is to render a bit of text:

React.createElement('h1', null, 'Hello World');

The children (above: 'Hello World') can also be another ReactElement!


Lets say we want to add a <div class="wrapper"> around our heading.
We use React.createElement to render a div with a className of
'wrapper', and then pass our heading in as the child:

React.createElement('div', { className: 'wrapper' },


React.createElement('h1', null, 'Hello World')
)
This will render this HTML:

<div class="wrapper">
<h1>Hello World</h1>
</div>

(JSBin)

This .wrapper div might have a max-width and other styling associated
with it. By reusing this element, we make sure our application is consistent
since it has the same styling everywhere! This is what components are for.

Components

To create a ReactComponent we write a function that returns a


ReactElement:

var Wrapper = function(props) {


return React.createElement('div', { className: 'wrapper' });
}

We can then use these components like any DOM Node by passing it into
a createElement call:

React.createElement(Wrapper);

Our wrapper component isnt very useful so far, since it doesnt render its
children:

React.createElement(Wrapper, {}, 'Hello World!');

This is because our component function gets passed the properties


(props). In the last example we didnt use the properties we got passed
from the createElement(Wrapper) call at all!
Lets render the children that our Wrapper gets passed:

var Wrapper = function(props) {

return React.createElement('div', { className: 'wrapper' }, props.childr


}

Now the above example works perfectly:

React.createElement(Wrapper, {}, 'Hello World!');

Lets try rendering our heading inside our Wrapper component:

React.createElement(Wrapper, null,
React.createElement('h1', null, 'Hello World')
)

(JSBin)

Amazing! Now we have a reusable Wrapper component that could


make sure every page across our application has consistent styling.

JSX

You might have seen React code samples floating around, and something
that mightve struck you is the weird HTML-ish syntax in the JavaScript
code that is used by most of the community.

This syntactic sugar is called JSX, and is nothing but a wrapper for
React.createElement!

Instead of calling React.createElement manually, we can use JSX to make


the code look more like the rendered HTML:

<Wrapper>
<h1 className="heading">Hello World</h1>
</Wrapper>

is the same thing as

React.createElement(Wrapper, null,
React.createElement('h1', {className: 'heading'}, 'Hello World')
)

Using JSX is a bit tricky: since its a non-standard extension of


JavaScript no browser will understand it. This means we have to
transpile (compile JavaScript to JavaScript) our code with a build tool
thankfully, react.jsbin.com does that automatically for us, so we dont
have to worry about it.

Passing properties to our components is as easy as writing them as


attributes on these HTML-like tags, and to add children we simply wrap
them! The nice thing about JSX is that we can use JavaScript code in JSX
by wrapping it in curly braces.

Lets convert our Wrapper component to use JSX:

var Wrapper = function(props) {


return (
<div className="wrapper">{ props.children }</div>
);
};

(JSBin)

Its not that different from calling createElement manually, but JSX is
much nicer to read and understand!

JSX is the preferred way of writing react applications because it is


easier to read and understand. Thus, this tutorial will from now on use
JSX.
Classes

As mentioned in the Why React? section, React has the virtual DOM to
minimize rerendering when the application state changes. But what is
application state and how do we manage it in React?

Any real world application will have state. State can be anything and
everything, ranging from this checkbox is checked over that modal is
open to this data was fetched.

As a simple example of state, lets create a Counter component that


counts how often weve clicked a button! Our Wrapper component above
was written as a functional component. To create stateful components,
we have to use a slightly different notation to create components the
class notation!

To create a stateful component, we create a new class that extends


React.Component. (React.Component is a base we can build upon that
React provides for us) We assign it a render method from which we return
our ReactElements, not unlike the functional component:

class Counter extends React.Component {


render() {
return (
<p>This is the Counter component!</p>
);
}
}

We can then render this component just like the other components with
ReactDOM.render:

ReactDOM.render(
<Counter />,
document.getElementById('container')
);
(JSBin)

Lets make a separate Button component, whichll take a prop called text.
Well make this component a functional one again, since it wont need to
store any state:

var Button = function(props) {


return (
<button>{ props.text }</button>
);
}

Then we render our Button into our Counter with a text of Click me!:

class Counter extends React.Component {


render() {
return (
<div>
<p>This is the Counter component!</p>
<Button text="Click me!"/>
</div>
);
}
}

(JSBin)

Now lets increase a number every time a user clicks on our Button by
using an onClick handler:

class Counter extends React.Component {


render() {
return (
<div>
<p>This is the Counter component!</p>
<Button text="Click me!" onClick={function() { console.log('click!
</div>
);
}
}
Here we need to differentiate between react components and real DOM
nodes. Event handlers, like onClick, onMouseOver, etc., only work when
they are attached to a real DOM node. The above example doesnt work,
because were only attaching it to a ReactComponent. You can click the
Button however much you like, you will never see "click!" in the console!

To make this work, we have to attach the onCLick handler to the native
DOM button node inside the Button component:

var Button = function(props) {


return (
<button onClick={props.onClick}>{ props.text }</button>
);
}

(JSBin)

Yey, this works!

We dont actually want to log click! every time we click the button
though we want to count the times it has been clicked! To do that, we
have to add state to our Counter component. State is a plain object in
react, which can have as little or as many properties as you like! Out state
will have a clicks property, which initially is zero and increments by one
with each click.

The first thing we need to do is set the initial state. Classes have a
constructor that is called when the class is first initialised, which we can
use to assign the initial state to our component:

class Counter extends React.Component {


constructor() {
super();
this.state = {
clicks: 0
};
}
render() { }
}

That alone wont do anything though, we dont see that number anywhere
on the page! (JSBin) To access the current state of our component
anywhere within our component we access this.state. Lets render the
current number of clicks as text for a start:

class Counter extends React.Component {


constructor() {
super();
this.state = {
clicks: 0
};
}

render() {
return (
<div>
<p>This is the Counter component! The button was clicked { this
<Button text="Click me!" onClick={function() { console.log('click!
</div>
);
}
}

(JSBin)

The { } notation in JSX works with any variable. var favoriteFood =


'Pizza'; in combination with I love { favoriteFood }! will output I
love Pizza!!

Our Counter now looks like this, but clicking on the button doesnt
increment the click count!
To change the state of a component, we use the this.setState helper
function which React provides. Lets add an increment method to our
Counter, which increments the clicks state by one, and call
this.increment when our Button is clicked!

class Counter extends React.Component {


constructor() {
super();
this.state = {
clicks: 0
};
}

increment() {
this.setState({
clicks: this.state.clicks + 1
});
};

render() {
return (
<div>
<p>This is the Counter component! The button was clicked { this
<Button text="Click me!" onClick={this.increment} />
</div>
);
}
}

The problem here is that this is undefined in increment because of the


way ES6 classes work the easiest way to fix this is to bind the context
of increment to the class in the constructor like so:

class Counter extends React.Component {


constructor() {
super();
this.state = {
clicks: 0
};
this.increment = this.increment.bind(this);
}

increment() {
this.setState({
clicks: this.state.clicks + 1
});
};

render() {
return (
<div>
<p>This is the Counter component! The button was clicked { this
<Button text="Click me!" onClick={this.increment} />
</div>
);
}
}

(JSBin)

Now it works, our Counter correctly increments the number when the
button is clicked!

Now that we understand React we know everything we need to know to


get started with building our app. Continue with Chapter 2: The first
app!

Additional material

This section at the end of each chapter will contain a few more links to
articles of related topics.

Official React Docs


JSX in depth
JSX Looks Like An Abomination, But its Good for You

Author
Max Stoiber @mxstbr

Max is the creator of react-boilerplate, one of the most popular react


starter kits, the co-creator of Carte Blanche and he co-organises the
React.js Vienna Meetup. He works as an Open Source Developer at
Thinkmill, where he takes care of KeystoneJS.