A JavaScript library that manages the UI.
React enables you to express in a declarative way what your UI should look like at any point in time; while building your app with little, reusable blocks: components.
A native DOM component is the simplest component you can get in React, it's basically how React represents a DOM element (e.g. <br />
).
These component can take parameters, they're called props. These props can either be:
className
)role
)onClick
)
About events, it has to be noted that they're not like
element.onclick = func
, as for performance reasons, React uses event delegation.
These elements are represented in JSX (a little JavaScript syntax extension that allows you to write XML in your regular JavaScript code) like this:
<hr className="Separator" />
They can contain children:
<div className="Menu">
<a className="Menu-item" href="/about">
About page
</a>
</div>
They can have computed content and props:
const aboutPageLink = "/about"
const aboutPageLabel = "About page"
const callback = console.log.bind(console)
<div className="Menu">
<a
className="Menu-item"
href={aboutPageLink}
onClick={callback}>
{aboutPageLabel}
</a>
</div>
It's basically like writing an HTML template, with a few exceptions for the attribute names, so that they fit their DOM property counterparts:
class
is written className
for
is written htmlFor
Another particularity is that if you want to set the innerHTML
property of a node, you have to pass a dangerouslySetInnerHTML
prop containing an object of shape {__html: string}
.
A composite component is a composition of native DOM elements, events and behaviour that you define. In order to do so, you got to create component classes.
Let's create one:
// `Component` is the base class we'll extend to create our component class
import React, {Component} from "react"
// As `Button` is a JavaScript class, it must be written in PascalCase
// This is the way JSX differenciates a Native DOM component from a composite
// component
class Menu extends Component {
render() {
// The render method is what outputs the nodes.
// NOTE: there must be only one root node returned.
return (
<div className="Menu">
<a className="Menu-item" href="/about">
About page
</a>
</div>
)
}
}
Here, I've got a Menu
component that will output <div className="Menu">
& its children.
To use a composite component, you just have to call it like a Native DOM component:
<Menu />
A composite component can also take arbitrary props:
import React, {Component} from "react"
class Menu extends Component {
render() {
// props are put in `this.props`
return (
<div className="Menu">
<a className="Menu-item" href={this.props.aboutPageLink}>
{this.props.aboutPageLabel}
</a>
</div>
)
}
}
// and then call this with props
<Menu aboutPageLink="/about" aboutPageLabel="About Page"/>
In order to make your components reusable with a relative safety, it is considered good pratice (rightfully) to define what type of props you expect:
// get `PropTypes`, which contains the type-checking methods
import React, {Component, PropTypes} from "react"
class Menu extends Component {
// the `propTypes` static property will contain the signature of
// your component
static propTypes = {
// a prop can be required
aboutPageLink: PropTypes.string.isRequired,
// or optional
aboutPageLabel: PropTypes.string,
}
// you can also specify default props
static defaultProps = {
aboutPageLink: "/",
aboutPageLabel: "",
}
render() {
// props are put in `this.props`
return (
<div className="Menu">
<a className="Menu-item" href={this.props.aboutPageLink}>
{this.props.aboutPageLabel}
</a>
</div>
)
}
}
// the following code will warn in the console, as you provided the wrong
// type for `aboutPageLabel`.
<Menu aboutPageLink="/about" aboutPageLabel={0}/>
Alright, let's build a Dropdown
component.
import React, {Component, PropTypes} from "react"
class Dropdown extends Component {
// we'll take a list of items, which will contain a label, and a value
static propTypes = {
items: PropTypes.arrayOf(
PropTypes.shape({
value: PropTypes.any.isRequired,
label: PropTypes.string.isRequired,
}),
),
}
render() {
return (
<div className="Dropdown">
<button className="Dropdown-button">
Dropdown
</button>
<ul className="Dropdown-items">
{/* you can use plain old JavaScript in your render method*/}
{this.props.items.map((item) => {
// in order to make react know which item is which when they change
// (like when sorting or filtering an array), you have to use a
// unique `key` prop in dynamic children.
// in our case, the value is unique.
return (
<button key={item.value}>
{item.label}
</button>
)
})}
</ul>
</div>
)
}
}
const items = [
{
item: "foo",
value: 1,
},
{
item: "bar",
value: 2,
},
{
item: "baz",
value: 3,
},
]
<Dropdown items={items}/>
Here, we've got the basic display, but we need our dropdown to be dynamic. As no other components should be aware of the fact the dropdown is opened or closed, we're going to use the optional composite component state:
import React, {Component, PropTypes} from "react"
class Dropdown extends Component {
// we'll take a list of items, which will contain a label, and a value
static propTypes = {
items: PropTypes.arrayOf(
PropTypes.shape({
value: PropTypes.any.isRequired,
label: PropTypes.string.isRequired,
}),
),
}
// initial state
state = {
// the dropdown is closed by default
opened: false,
}
render() {
return (
<div className="Dropdown">
<button className="Dropdown-button">
Dropdown
</button>
{/*
in JSX, `null`, `undefined` & `false` are considered empty.
therefore, if `this.state.opened` is `false`,
<ul className="Dropdown-items"> wont be rendered, if it `true`,
the expression after `&&` is evaluated, so we have our element
displayed.
*/}
{this.state.opened && <ul className="Dropdown-items">
{this.props.items.map((item) => {
return (
<button key={item.value}>
{item.label}
</button>
)
})}
</ul>}
</div>
)
}
}
Now, let's manipulate this state when we get a user input:
import React, {Component, PropTypes} from "react"
class Dropdown extends Component {
// we'll take a list of items, which will contain a label, and a value
static propTypes = {
items: PropTypes.arrayOf(
PropTypes.shape({
value: PropTypes.any.isRequired,
label: PropTypes.string.isRequired,
}),
),
}
// initial state
state = {
// the dropdown is closed by default
opened: false,
}
handleButtonClick(event) {
// `this.setState` takes an object, merges it into the
// existing `this.state` and then triggers a render.
this.setState({
opened: !this.state.opened,
})
}
render() {
return (
<div className="Dropdown">
<button
className="Dropdown-button"
onClick={(e) => this.handleButtonClick(e)}>
Dropdown
</button>
{this.state.opened && <ul className="Dropdown-items">
{this.props.items.map((item) => {
return (
<button key={item.value}>
{item.label}
</button>
)
})}
</ul>}
</div>
)
}
}
You can also call this.forceUpdate()
to trigger a render without calling this.setState()
.
Components can also receive children elements, which can be useful:
import React, {Component, PropTypes} from "react"
class Button extends Component {
render() {
// the `{...object}` syntax in JSX merges `object` in `props`.
return (
<button {...this.props} className="Button">
{/* you can reuse children */}
{this.props.children}
</button>
)
}
}
And even manipulate them:
import React, {Component, PropTypes, Children} from "react"
class SomeWrapper extends Component {
render() {
return (
<div {...this.props} className="SomeWrapper">
{Children.map(this.props.children, (child, index) => {
// each child will be wrapped in a `SomeWrapper-item` div element.
return (
<div className="SomeWrapper-item" key={index}>
{child}
</div>
)
})}
</div>
)
}
}
Any component has a lifecycle, as it:
setState
React gives us hooks to interact with these events in our component:
componentWillMount
, when the component is about to mountcomponentDidMount
, when the component just mountedcomponentWillReceiveProps(nextProps)
, when the component receives new props from its parentcomponentWillUpdate(nextProps, nextState)
, just before a new render is about to occurcomponentDidUpdate(previousProps, previousState)
, just after a new render has occuredshouldComponentUpdate(nextProps, nextState)
, that lets you decide whether (true
) or not (false
) a render should occur given the next props & state.componentWillUnmount
, before the component unmounts.
NOTE: The is no
componentDidUnmount
because the component instance is destroyed at that point
Renders the reactElement
in the DOM node
.
example:
const helloworld = (
<div>
helloworld
</div>
)
React.render(helloworld, document.getElementById("App"))
// #App will now contain a div with a `helloworld` text content.
Unmounts any component mounted at a given node. It returns true
if there was a component to unmount, and false
if not.
Returns the real root DOM element of reactComponent
. Useful for getting DOM readings like value
, getBoundingClientRect()
& stuff.
const aboutPageLink = "/about"
const aboutPageLabel = "About page"
<div className="Menu">
<a className="Menu-item" href={aboutPageLink}>
{aboutPageLabel}
</a>
</div>
outputs basic function calls.
const aboutPageLink = "/about"
const aboutPageLabel = "About page"
React.createElement("div", {className:"Menu"},
React.createElement("a", {className:"Menu-item", href: aboutPageLink},
aboutPageLabel
)
)