React intro


"Exotic" stateless functional component

function DemoComponent(props) {
  console.log(props);
  return React.createElement(
    'div',
    { style: { background: 'navy', color: 'yellow' } },
    'Hello world',
    props.name
  );
}

ReactDOM.render(
  React.createElement(
    DemoComponent,
    { name: 'Vasya' }
  ),
  document.querySelector('#content')
);

statefull component

const r = React.createElement

class DemoComponent extends React.Component {
  constructor() {
    super(...arguments);
    this.state = {
      login: 'Vasya',
      password: '',
      showPassword: false
    }
    this.updateLogin = this.updateLogin.bind(this)
    this.setShowPassword = e => this.setState({ showPassword: e.target.checked })
    this.updatePassword = e => this.setState({ password: e.target.value })
  }

  updateLogin(e) {
    // никогда не сохранять ссылку на этот объект события e
    this.setState({ login: e.target.value });
  }

  render() {
    return r(
      'form', {},
      r(
        'label', {},
        r(
          'input', { type: 'text', placeholder: 'login',
            value: this.state.login,
            onChange: this.updateLogin
          }
        ),
        r(
          'input', { type: this.state.showPassword ? 'text : ''password',
          placeholder: 'password', value: this.state.password,
          onChange: this.updatePassword
          }
        ),
        r(
          'input', { type: 'checkbox',
            value: this.state.showPassword,
            onChange: this.setShowPassword
          },
          'Show password'
        )
      )
    );
  }
}

Pokedex

class DemoComponent extends React.Component {
  constructor() {
    super(...arguments);
    this.state = {
      pokemons: []
    }

    fetch('https://pokeapi.co/api/v1/pokemon/?limit=10')
      .then(d => d.json())
      .then(data => this.setState({ pokemons: data.objects }));
  }

  render() {
    return r(
      'ul',
      {},
      this.state.pokemons.map(p => r(
        'li',
        { key: p.pkdx_id },
        r('img', {src: `http://pokeapi.com/media/img/${p.pkdx_id}.png`})
      ))
    );
  }
}

перепишем на JSX

class Pokemon extends React.Component {
  shouldComponentUpdate(newProps, newState) {
    // this.props - предыдущее
    // newProps - новое
    // нужно ли перерисовывать true/false; по умолчанию true
    if (newProps.pokemon == this.props.pokemon) return false;
  }

  render() {
    const { pokemon, onDblClick } = this.props;
    return (
      <li>
        <img src=`http://pokeapi.com/media/img/${pokemon.pkdx_id}.png`
          onDblClick={() => onDblClick(pokemon)}
         />
        ${pokemon.name}
      </li>
    )
  }
}

class DemoComponent extends React.Component {
  constructor() {
    super(...arguments);
    this.state = {
      pokemons: []
    }

    this.onPokemonRemove = pokemon => {
      const newPokemons = this.state.pokemons.filter(p => p !== pokemon)
      this.setState({ pokemons: newPokemons })
    }

    fetch('https://pokeapi.co/api/v1/pokemon/?limit=10')
      .then(d => d.json())
      .then(data => this.setState({ pokemons: data.objects }));
  }

  componentDidMount() {
    const scrollbar = new GeminiScrollbar({element: this.refs.list})
    scrollbar.create()
  }

  render() {
    return (
      <ul ref="list">
        { this.state.pokemons.map((p) => <Pokemon key={p.pkdc_id} pokemon={p}
        onClick={this.onPokemonRemove}
         />)}
      </ul>
    );
  }
}

ReactDOM.render(
  <DemoComponent />,
  document.querySelector('#content')
);

componentWillReceiveProps(nextProps) - единственный метод, в котором setState не вызовет render. Например для таблица рейтинга игроков (когда рейтинг меняется - рисовать стрелочки кто куда переместился)