There are many good tutorials out there. This one was written based on them as an introduction of React to my team.
It tries to give you the essentials for the basic understanding of React and best practices. I hope it gives you a general view of the most important concepts.
Note that to use React you don’t need to use all the ecosystem, which many times, it’s what makes difficult to begin. However, you should know javaScript and I encourage you to learn ES6 and keep updated programming practices.
This post is targeted at people who know ES6, including the concepts of modular JS (if you know the basics of React, then it’s just JavaScript!).
React components are very simple. You can think of them as simple functions that take in props
and state
(discussed later) and render HTML. They should follow the single responsibility principle, that is, a component should ideally only do one thing. If it ends up growing, it should be decomposed into smaller subcomponents. This is composition.
React provides custom methods and lifecycle methods / hooks you can use. It provides will methods, which are called right before something happens, and did methods which are called right after something happens. It also provides this.setState({ })
api to change the state of the component inside this methods, or inside your custom methods (like event handlers).
Components have three main parts of their lifecycle:
(adapted from here)
import React from 'react';
// this will be our component:
const MyReactComponent = React.createClass({
propTypes: {
// The propTypes object allows you to validate props being passed to your components.
},
// An array of objects each of which can augment the lifecycle methods
mixins: [],
// Functions that can be invoked on the component without creating instances
statics: {
aStaticFunction() {}
},
// The object returned by this method sets the initial value of this.state
getInitialState() {
return {};
},
// The object returned by this method sets the initial value of this.props
// If a complex object is returned, it is shared among all component instances
getDefaultProps() {
return {};
},
//--------- Lifecycle Methods ------------//
// Invoked once BEFORE first render
componentWillMount() {
// Calling setState here does not cause a re-render
},
// The data returned from render is neither a string nor a DOM node.
// It's a lightweight description of what the DOM should look like.
// Inspects this.state and this.props and create the markup.
// When your data changes, the render method is called again.
// React diff the return value from the previous call to render with
// the new one, and generate a minimal set of changes to be applied to the DOM.
render() {
// Returns the jsx markup (React has no templates) for a component
// Should never update this.state or this.props
return (<div></div>);
},
// Invoked once, only on the client (not on the server), immediately AFTER the initial rendering occurs.
componentDidMount() {
// You can access any refs to your children
// (e.g., to access the underlying DOM representation - ReactDOM.findDOMNode).
// The componentDidMount() method of child components is invoked before that of parent components.
// If you want to integrate with other JavaScript frameworks,
// set timers using setTimeout or setInterval,
// or send AJAX requests, perform those operations in this method.
},
// Invoked whenever there is a prop change
// Called BEFORE a second render
// Not called for the initial render
componentWillReceiveProps(nextProps) {
// Previous props can be accessed by this.props
// Calling setState here does not trigger an an additional re-render
},
// Determines if the render method should run in the subsequent step
// Called BEFORE a second render
// Not called for the initial render
shouldComponentUpdate(nextProps, nextState) {
// If you want the render method to execute in the next step
// return true, else return false
return true;
},
// Called IMMEDIATELY BEFORE a second render
componentWillUpdate(nextProps, nextState) {
// You cannot use this.setState() in this method
},
// Called IMMEDIATELY AFTER a second render
componentDidUpdate(prevProps, prevState) {
},
// Called IMMEDIATELY before a component is unmounted from the DOM
componentWillUnmount() {
}
});
export default MyReactComponent
Lifecycle diagram - See a bigger image
You can now use this component:
import ReactDOM from 'react-dom'
import MyReactComponent from './MyReactComponent.jsx'
ReactDOM.render(<MyReactComponent />, document.getElementById('example'))
render()
method:import React from 'react'
import MyReactComponent from './MyReactComponent.jsx'
const MyOtherComponent = React.createClass({
render() {
return(
<MyReactComponent />
);
}
});
Give it five minutes.
JSX lets you create JavaScript objects using HTML syntax. Usually this is the return value of the render()
method. JSX is completely optional; you don’t have to use JSX with React. You can create React elements in plain JavaScript using React.createElement, which takes a tag name or component, a properties object, and variable number of optional child arguments.
var child1 = React.createElement('li', null, 'First Text Content');
var child2 = React.createElement('li', null, 'Second Text Content');
var root = React.createElement('ul', { className: 'my-list' }, child1, child2);
React.render(root, document.getElementById('example'));
To generate a link in React using pure JavaScript you’d write:
// this is a comment
React.createElement('a', {href: 'https://facebook.github.io/react/'}, 'Hello!')
With JSX this becomes:
{/* this is a comment */}
<a href="https://facebook.github.io/react/">Hello!</a>
All attributes are camelCased and the attributes class
and for
are className
and htmlFor
, respectively, to match the DOM API specification.
You can pass custom attributes - this is what is called props
.
The tags can be self closed, except if they have content.
<MyComponent myProp={/* this can be a string, an array, an object, an variable, a function, etc */} />
You can pass your event handler as a camelCased prop similar to how you’d do it in normal HTML (event delegation).
<button onClick={this.handleBtnClick}>Click Me</button>
You can use javascript expressions and variables inside jsx using { }
<span>
<p>{iAmIVariable}</p>
<div>
{ IExist ? <p>{IExist}</p> : null }
</div>
</span>
Limitations:
The main responsibility of a Component is to translate raw data into rich HTML. With that in mind, the props
and the state
together constitute the raw data that the HTML output derives from.
State – created within the component. Can change. The state starts with a default value when a Component mounts and then can change in time (mostly generated from user events or ajax calls). It’s a serializable representation of one point in time—a snapshot. A Component manages its own state internally, and can access it as this.state
. You could say the state is private.
Props – short for “properties”. They’re passed as attributes in JSX syntax from the ‘parent/owner component’. You should think of these as immutable within the component, that is, never write to this.props
. They just change according to the state change.
React is all about building reusable components. In fact, the only thing you do is build components. Since they’re so encapsulated, components make code reuse, testing, and separation of concerns easy.
The data should always flow from top to bottom - as props
.
In React, an owner is the component that sets the props
of other components. More formally, if a component X
is created in component Y
’s render()
method, it is said that X
is owned by Y
.
const IAmTheOwner = React.createClass({
getInitialState() {
return {
data: 'just passing data down the tree'
}
},
render() {
return(
<IAmOwned IHaveProps={this.state.data} />
);
}
});
const IAmOwned = React.createClass({
render() {
return(
<p>{this.props.IHaveProps}</p>
);
}
// result: <p>just passing data down the tree</p>
});
When you create a React component instance, you can include additional React components or JavaScript expressions between the opening and closing tags. Parents can read its children by accessing the special this.props.children
prop.
const ParentComponent = React.createClass({
render(
<div>
{ this.props.children }
</div>
);
});
// Usage:
<ParentComponent>
<ChildrenComponent />
</ParentComponent>
state is optional. Since state increases complexity and reduces predictability, a Component without state is preferable. Even though you clearly can’t do without state in an interactive app, you should avoid having too many Stateful Components.
render()
function and all their logic revolves around the props they receive. This makes them very easy to follow (and test for that matter). We sometimes call these dumb or presentational components.Use props (this.props) to access parameters passed from the parent/owner. Use state (this.state) to manage dynamic data.
Follow the colors to understand the state and props flow between components. See a bigger version
Not to be confused with the render()
function that you define on your component (and which returns a virtual DOM element), ReactDOM.render()
will return a reference to your component’s backing instance.
In order to get a reference to a React component, you can either use this
to get the current React component, or you can use a ref
to get a reference to a component you own.
These refs (references) are especially useful when you need to: find the DOM markup rendered by a component (for instance, to position it absolutely), use React components in a larger non-React application, or transition your existing codebase to React.
If you need access to the underlying DOM node for that component, you can use ReactDOM.findDOMNode
as an “escape hatch” but we don’t recommend it since it breaks encapsulation and in almost every case there’s a clearer way to structure your code within the React model.
const MyComponent = React.createClass({
handleClick() {
// Explicitly get the input value using the raw DOM API.
const inputValue = this.refs.myInput.value;
console.log(inputValue);
},
render() {
// The ref attribute saves a reference to the
// component to this.refs.myInput **when the component is mounted**.
return (
<div>
<input type="text" ref="myInput" defaultValue="Hello!" />
<button onClick={this.handleBtnClick}>Click Me</button>
</div>
);
}
});
ReactDOM.render(
<MyComponent />,
document.getElementById('example')
);
You can write your components in 3 different ways:
React.createClass({ }): The one we have being using. We pass some methods in a JavaScript object to React.createClass() to create a new React component. This methods will have autobinding of this
: every method is automatically bound to its component instance. You can use Mixins. You CAN use ES6 syntax.
import React from 'react';
const MyComponent = React.createClass({
propTypes: {
},
getInitialState() {
return {
};
}, //<--- comma! Its an object
getDefautProps() {
return {
};
},
handleBtnClick() {
console.log(this);
// `this` here refers to the component instance
},
render() {
return (
<div>
<p>{this.props.someProps}</p>
<button onClick={this.handleBtnClick}>Click Me</button>
</div>
);
}
});
ES6 Class: Real JS ES6 classes. No autobinding. No Mixins, but you can use HOC. No getInitialState or componentWillMount - state, getDefaultProps and propTypes are really just properties on the constructor.
import React from 'react';
class MyComponent extends React.Component{
// pass in the props of React.Component
constructor(props) {
super(props);
// this is equivalent to getInitialState
this.state = {
};
}
handleBtnClick() {
console.log(this);
// `this` here refers to the component instance *after* you bind it
}
render() {
return (
<div>
<p>{this.props.someProps}</p>
<button onClick={this.handleBtnClick.bind(this)}>Click Me</button>
</div>
);
}
}
MyComponent.propTypes = { };
MyComponent.defaultProps = { };
In ES6 classes, you can bind the methods to the instance of your component in different ways that the previous one:
// On the constructor
class MyComponent extends React.Component{
constructor(props) {
super(props);
this.handleBtnClick = this.handleBtnClick.bind(this);
}
handleBtnClick() {
console.log(this);
}
render() {
return (
<div>
<p>{this.props.someProps}</p>
<button onClick={this.handleBtnClick}>Click Me</button>
</div>
);
}
}
// Using ES7+ Property Initializers + arrow functions
class MyComponent extends React.Component{
constructor(props) {
super(props);
}
handleBtnClick = () => {
console.log(this);
}
render() {
return (
<div>
<p>{this.props.someProps}</p>
<button onClick={this.handleBtnClick}>Click Me</button>
</div>
);
}
}
Stateless functional components: Since React 0.14, you can take props
as a function argument and return the element you want to render. If you don’t have state or refs, or your component doesn’t need lifecycle methods, prefer this method of defining a component:
// A functional component using an ES2015 (ES6) arrow function:
const MyComponent = (props) => {
const handleBtnClick = () => {
console.log(this);
};
return (
<div>
<p>{props.someProps}</p>
<button onClick={handleBtnClick}>Click Me</button>
</div>
);
};
// Or with destructuring:
const MyComponent = ({someProps}) => {
const handleBtnClick = () => {
console.log(this);
};
return (
<div>
<p>{someProps}</p>
<button onClick={handleBtnClick}>Click Me</button>
</div>
);
};
MyComponent.propTypes = { };
MyComponent.defaultProps = { };
Checkout this great filterable cheat sheet with direct links to the documentation.
Checkout this blog posts:
And all the post in the React category. –> more comming soon
14 Feb 2016 #reactjs #javascript #frontend
Someone once said "She's very enthusiastic and eager to test everything tech-related. Loves to get every front-end platform working automagically. She programmed her own Pebble and comes from the beautiful region of Alentejo."