Skip to content

Instantly share code, notes, and snippets.

@remitbri
Forked from bloodyowl/00.Intro.md
Last active August 29, 2015 14:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save remitbri/9e7b636e7dfa5d413b1d to your computer and use it in GitHub Desktop.
Save remitbri/9e7b636e7dfa5d413b1d to your computer and use it in GitHub Desktop.

React

A JavaScript library that manages the UI.

What does it do?

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.

Component API

Native DOM component

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:

  • DOM element properties (like className)
  • DOM element attributes (like role)
  • DOM events listeners (like 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}.

Composite component

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.

the basics

Let's create one:

// `Component` is the base class we'll extend to create our component class
import React, {Component} from "react"

// As `Menu` 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 JS, the && operator produces the value of the second operand if
          the first operand is truthy.
          Therefore, if `this.state.opened` is `true`,
          <ul className="Dropdown-items"> will be rendered;
          if `this.state.opened` is false, our element won't be 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>
    )
  }
}

lifecycle

Any component has a lifecycle, as it:

  • is mounted in the DOM
  • potentially updates in it locally, using setState
  • potentially updates when it get new props from its parent component
  • is unmounted

React gives us hooks to interact with these events in our component:

  • componentWillMount, when the component is about to mount
  • componentDidMount, when the component just mounted
  • componentWillReceiveProps(nextProps), when the component receives new props from its parent
  • componentWillUpdate(nextProps, nextState), just before a new render is about to occur
  • componentDidUpdate(previousProps, previousState), just after a new render has occured
  • shouldComponentUpdate(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

Top Level API

React.render(reactElement, node[, callback])

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.

bool React.unmountComponentAtNode(node)

Unmounts any component mounted at a given node. It returns true if there was a component to unmount, and false if not.

DOMElement React.findDOMNode(reactComponent)

Returns the real root DOM element of reactComponent. Useful for getting DOM readings like value, getBoundingClientRect() & stuff.

JSX

What does JSX compiles to?

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
  )
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment