Repozytorium Web Developera

React, Redux, Flux, MobX

Useful links - React

Recommended React learning path for beginners:

  1. Eventually (in Polish) Wprowadzenie do React wraz z przykładem projektu
  2. React vs jQuery - a same application in both tools (for those familiar with jQuery)
  3. React Official Docs - Quick Start
  4. Build Your First Production Quality React App + code
  5. Your first applications in React with Create React App

About MobX:

  1. Read README.md of Github repo
  2. Eventually (in Polish) post na blogu o MobX
  3. Eventually (in Polish) post o połączeniu React i MobX - router
  4. Ten minute introduction to MobX and React
  5. Eventually article on Medium about core concept of MobX by it author Michel Weststrate
  6. Eventually presentation by Michel Weststrate "Michel Weststrate: Real World MobX — ReactNext 2016"
  7. Egghead course Manage Complex State in React Apps with MobX
  8. Mobx tutorial at js.org

About Redux/Flux:

  1. Getting Started with Redux: An Intro
  2. Egghead Getting Started with Redux + code/notes
  3. Why use Redux over Facebook Flux?

About Webpack:

React information

JSX syntax

Example

JSX code:


<MyButton color="blue" shadowSize={2}>
  Click Me
</MyButton>
Compiles into:

React.createElement(
  MyButton,
  {color: 'blue', shadowSize: 2},
  'Click Me'
)

Components names must be capitalized.

ES6 Map.forEach() and JSX

Source - forEach over es6 Map in JSX

Map.forEach() doesn't return anything so we can't iterate over Map() object using this method. Instead we have to use Array.map() but first we have to convert a Map object to an Array. We can achieve it using method entries():


render({

    this.store.todos.forEach(function(todo, key) {
      ...
    })

    // doesnt return anything, so instead we have to use

    this.store.todos.entries().map(function(result) {
      const key = result[0]
      const todo = result[1]
      ...
    })

})

Components

Components names must be capitalized.

React elements are immutable. Once you create an element, you can't change its children or attributes.

React functions are "pure" because they do not attempt to change their inputs, and always return the same result for the same inputs. All React components must act like pure functions with respect to their props.

Passing props to component and displaying it

Examples of displaying props in a component written in ES6/JSX:


import React from 'react';

exports class Greeter extends React.Component {
  render() {
    return (
      <div>Hello {this.props.name} !</div>
    )
  }
}

Greeter.propTypes = {
  name: React.PropTypes.string
}

Code of an applications that is passing a prop to a component:


import React from 'react';
import Greeter from './greeter';

export default class App extends React.Component {
  render() {
    return (
      <div>
        <Greeter name="Bob" />
      </div>
    )
  }
}

Container Component approach

A container of a component is responsible for fetching data. Below you can see an example of a container component, that is passing its state to the component:


class CommentListContainer extends React.Component {
  state = { comments: [] };
  componentDidMount() {
    fetchSomeComments(comments =>
      this.setState({ comments: comments }));
  }
  render() {
    return <CommentList comments={this.state.comments} />;
  }
}

Below is a component, which data is passed by a container - in this example comments were passed:


const CommentList = props =>
  <ul>
    {props.comments.map(c => (
      <li>{c.body}—{c.author}</li>
    ))}
  </ul>

Below is an example without using Container Component approach:


class CommentList extends React.Component {
  this.state = { comments: [] };

  componentDidMount() {
    fetchSomeComments(comments =>
      this.setState({ comments: comments }));
  }
  render() {
    return (
      <ul>
        {this.state.comments.map(c => (
          <li>{c.body}—{c.author}</li>
        ))}
      </ul>
    );
  }
}

State and lifecycle

The state will be only updated when you use a setState() method, not by directly write to state property:


// Wrong, doesn't update a component.
this.state.comment = 'Hello';

// Correct.
this.setState({comment: 'Hello'});

State and state updates can be asynchronous, so don't rely on their values:


// Wrong
this.setState({
  counter: this.state.counter + this.props.increment,
});

// Correct
this.setState((prevState, props) => ({
  counter: prevState.counter + props.increment
}));

Handling events

Example of handling events:

In JavaScript, class methods are not bound by default. If you forget to bind this.handleClick and pass it to onClick, this will be undefined when the function is actually called.

class Toggle extends React.Component {
  constructor(props) {
    super(props);
    this.state = {isToggleOn: true};

    // This binding is necessary to make `this` work in the callback
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    this.setState(prevState => ({
      isToggleOn: !prevState.isToggleOn
    }));
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        {this.state.isToggleOn ? 'ON' : 'OFF'}
      </button>
    );
  }
}

ReactDOM.render(
  <Toggle />,
  document.getElementById('root')
);

create-react-app

React Router 4

react-router, react-router-dom

For webbrowser based project, use react-router-dom - DOM bindings for React Router.

react-router-dom


// using ES6 modules
import { BrowserRouter, Route, Link } from 'react-router-dom'

// using CommonJS modules
var BrowserRouter = require('react-router-dom').BrowserRouter
var Route = require('react-router-dom').Route
var Link = require('react-router-dom').Link
Routes

In a main component:


render() {
  return (
    <Switch>
      <Route exact path='/landing' component={Landing}/>
      <Dashboard>
        <Route path='/dashboard' component={Main}/>
        <Route path='/users' component={Users}/>
      </Dashboard>
      <Route exact path='/' component={Login}/>
    </Switch>
  )
}
Links

Add to a component:


render() {
  return (
    ...
    <Link to='/main'><Logo /></Link>
    ...
  )
}
Redirecting

Add to a component:


render() {
  return (
    ...
    {this.state.login && <Redirect to='/download' />}
    ...
  )
}

react-router

react-router-redux

React MobX

MobX with create-react-app

create-react-app doesn't support decorators. MobX can be used without them but development is faster and easier with them. Here you can find instructions how to enable decorators in the package:

If you don't want to use decorators, here you can find an example of an app with using MobX and standard syntax:

React + MobX + Router example

If you want to start development with this stack, I suggest you to start from understanding below boilerplate:

MobX forms

I haven't read but this can be good article about forms in MobX:

React Fela vs. Styled Components

fela i react-fela

createComponent example

Simple:


import { createComponent } from 'react-fela'

const label = props => ({
  fontSize: props.size,
  lineHeight: '200px',
  padding: 20
})

export default createComponent(label)

Advanced:


import React from 'react'
import { createComponent } from 'react-fela'

const Header = ({ title, className }) => (
  <div className={className}>
    {title}
  </div>
)

const rule = () => ({
  color: 'rgb(50, 50, 50)',
  fontSize: 100,
  padding: 50,
  ':hover': { animationDuration: '500ms' },
  '@media (max-width: 800px)': { fontSize: '40px' },
  animationDuration: '2s',
  animationIterationCount: 'infinite',
  animationName: {
    '0%': { color: 'green' },
    '50%': { color: 'blue' },
    '80%': { color: 'purple' },
    '100%': { color: 'green' }
  }
})

export default createComponent(rule, Header, ['title'])

connect example


import { connect } from 'react-fela'

const Header = ({ title, styles }) => (
  <header className={styles.container}>
    <h1 className={styles.title}>{title}</h1>
  </header>
)

const container = props => ({
  textAlign: 'center',
  padding: '20px',
  height: '200px'
})

const title = props => ({
  lineHeight: 1.2,
  fontSize: props.size,
  color: props.color
})

const Connectedheader = connect({
  container,
  title
})(Header)

ReactDOM.render(
  <Connectedheader
    title='Hello World'
    color='red'
    size={17} />,
  document.getElementById('app')
)