Skip to content

Instantly share code, notes, and snippets.

@JoseGonzalez321
Last active October 28, 2017 01:51
Show Gist options
  • Save JoseGonzalez321/73584a2bdd107c3d4c27d7725921db38 to your computer and use it in GitHub Desktop.
Save JoseGonzalez321/73584a2bdd107c3d4c27d7725921db38 to your computer and use it in GitHub Desktop.
Step by step guide on for the React Rockman Robot Masters App

Note: These are my personal notes for the presentation. Feel free to contribute or contact me for any clarifications.

  • Do npm install before the talk starts. It's a lot of dead time...and you know WIFI issues.

Add

constructor() {
    super();
    this.state = {
        robots: ['Proto Man', 'Mega Man']
    }
}

Inside render():

render() {
    return(
        <div>
            {this.state.robots.length}
        </div>
    )
}
  • Display the list
  render() {    
    return (
      <div>       
        How many I got: {this.state.robots.length}
      <ul>{this.state.robots.map((robot, i) =>(
          <li>{robot}</li>
        ))}
      </ul>
    </div>
    )
  }
  • Show js deconstrution
  render() {
    const { robots } = this.state;   
    
    return (
      <div>       
        How many I got: {robots.length}

        <ul>
        {robots.map(robot => (
          return (<li>{robot}</li>);
        ))}
        <ul>
      </div>
    )
  }

Get real data

Create new method getData()

getData() {    
  const url = 'http://localhost:5000/api/robot/'

  fetch(url)
    .then(response => response.json())
    .then(data => {
      this.setState({robots: data});
    })
}

call it from componentDidMount

componentDidMount() {    
    this.getData();
}

Change robots.map(...) to

{robots.map((robot, i) =>{
    return (
    <li key={robot.id}>
        <img height="40" width="40" src={Robot.avatar}/>
        {robot.name} - {robot.weakness}
    </li>
    );
})}

Create first stateless component

  • Create folder components
  • Create new file called RobotMaster.js

Use shortcut rsc to create stateless component and name it RobotMaster.

Add props as a parameter

const RobotMaster = (props) => {
    return (
        <div>
            
        </div>
    );
};

export default RobotMaster;

Copy the jsx from the robots.map function

<li key={robot.id}>
    <img height="40" width="40" src={Robot.avatar}/>
    {Robot.name} - {Robot.weakness}
</li>

Before return(), add

const { Robot } = props;

Example of deconstruction in JS.

Clean up the JSX. Remove robot.

Complete component should look like this:

import React from 'react';

const RobotMaster = (props) => {

  const { Robot } = props;

  return (
    <li>    
      <img height='40' width='40' src={Robot.avatar}/>
      {Robot.name} - {Robot.weakness}
    </li>
  );
};

export default RobotMaster;

Using component

Back in App.js. Import component

import RobotMaster from './components/RobotMaster'

Replace code inside robots.map() with new component.

Finished Render() shoud look like this:

  render() {
    const { robots } = this.state;
    return (
      <div>
        <div>{robots.length}</div>
        <ul>
          {robots.map(robot => (
            <RobotMaster Robot={robot}/>
          ))}
        </ul>
      </div>
    )
  }

Add CSS

Let's kick up a notch! Import base.css and remove app.css

+ import './stylesheets/base.css';
- ./stylesheets/base.css;

In the return (...) method, add id='shuffle' to the first div:

return (
+     <div id="shuffle">
        How many do I have? 
        {robots.length}
        <ul>
        {robots.map((robot, i) => {
          return (
            <RobotMaster key={robot.id} {...robot}/>
          );
        })}
        </ul>

      </div>
    );

Update RobotMaster.js

Add the following code:

<li className='list-item card list'>

Add a new div tag to include the avatar, name and id:

<div className='mug'>
  <img src={Robot.avatar} alt={Robot.name} />
  <div className='name'>{Robot.name}</div>
  <div className='serial'>Serial: {Robot.id}</div>
</div>

Add the weakness and image sprite sections

<div className='info'>
  <b>Weakness</b>
  <div>{Robot.weakness}</div>
</div>
<div className='other'>
  <img src={Robot.sprite1} className='sprite'/>
</div>

Note: If your results look odd, don't forget to zoom to 100% in the browser!!

Final result:

<li className='list-item card list'>
  <div className='mug'>
    <img src={Robot.avatar} alt={Robot.name} />
    <div className='name'>{Robot.name}</div>
    <div className='serial'>Serial: {Robot.id}</div>
  </div>
  <div className='info'>
    <b>Weakness</b>
    <div>{Robot.weakness}</div>
  </div>
  <div className='other'>
    <img src={Robot.sprite1} className='sprite'/>
  </div>
</li>

Creating Toggle button

Example of a component class

Add a new file in the Components folder. Name it Toggle.js.

Use the shor-cut: rcc. Set the spaces:2, if you have to.

Add the following code inside the render() method.

const { text, clickHandler } = this.props;

Change the return to:

<button onClick={clickHandler}>
    {text}
</button>

Let's use it!

Import Toggle.js in App.js

import Toggle from './Components/Toggle';

Use it!

Add new divs right beneath <div id='shuffle'>

<header>  
  <Toggle 
    text='All'
    clickHandler = {this.selectGameSerie}
  />  
</header>

<div style={{padding:15}}/> 

Add a new method called selectGameSerie

selectGameSerie(e) {
  if (this.state.currentGameSerie === e.target.textContent)
    return;
    
  this.setState( { currentGameSerie: e.target.textContent })
}

Add a new variable to the state in the constructor:

this.state = {
    robots: [],
+   selectedSeries: 'All'
};

Edit the getData() method to handle the selected series

+const {currentGameSerie} = this.state;

let url = 'http://localhost:5000/api/robot/';

+ (currentGameSerie !== 'All')
+    url = url + `series/${currentGameSerie}`;
}

Do not forget to hook up the event in the constructor!!

constructor() {
    super();
    this.state = {
      robots:[],
      currentGameSerie: 'All'
    }

+    this.selectGameSerie = this.selectGameSerie.bind(this);
  }

Also add the componentDidUpdate event. Add it under componentDidMount()

Even fires whenever the component updates. So we are using this as a way to get data with the proper selectedSeries

componentDidUpdate(prevProps, prevState) {
  if (this.state.currentGameSerie !== prevState.currentGameSerie) {
    this.getData();
  }
}

Back to Toggle for a face lift

Import classnames library

import classNames from 'classnames';

Add following code before return() method

const buttonClass = classNames ({
    'button-toggle': true,
    'no-icon': !icon,
    active,
});

Add a className to button:

<button className={buttonClass} onClick={clickHandler}>
    {text}
</button>

Final render should look like:

render() {
    const { text, icon, active, clickHandler } = this.props;
    const buttonClass = classNames ({
      'button-toggle': true,
      'no-icon': !icon,
      active,
    });

    return (
      <button className={buttonClass} 
              onClick={clickHandler}>       
        {text}
      </button>
    );
}

Still the toggling of color is not working :(

Let's fix that easily!

Fixing toggle color

Add active = {currentGameSerie === 'All'} to each Toggle button to toggle their active state.

    <Toggle
    text='All'
+   active = {currentGameSerie === 'All'}
    clickHandler = {this.selectGameSerie}
    />
    <Toggle
    text='2'
+   active = {currentGameSerie === '2'}
    clickHandler = {this.selectGameSerie}
    />
    <Toggle
    text='3'
+   active = {currentGameSerie === '3'}
    clickHandler = {this.selectGameSerie}
    />

Note: Do not forget to include currentGameSerie in the desconstruction

const {robots, currentGameSerie} = this.state;

Add the rest of the series. Copy/Paste the last Toggle syntax.

FlipMove!

In App.js, import library at the top

import FlipMove from 'react-flip-move';

Change the return section.

Replace <RobotMaster Robot={robot}/>

With

<FlipMove 
  easing="ease-in-out"
  duration={550}>
  <div key={robot.id}>
    <RobotMaster Robot={robot}/>
  </div>
</FlipMove>

Bonus

Add font-awesome icon in Toggle.js

const iconClass=`fa fa-fw fa-${icon}`;

and add a section <i className={iconClass} />

render() {
    const { text, icon, active, clickHandler } = this.props;
    const buttonClass = classNames ({
      'button-toggle': true,
      'no-icon': !icon,
      active,
    });
    
    const iconClass=`fa fa-fw fa-${icon}`;

    return (
      <button className={buttonClass} onClick={clickHandler}>
        <i className={iconClass} />
        {text}
      </button>
    );
}

Add a shuffle button!

import lodash

import { shuffle } from 'lodash';

Add new method:

sortShuffle() {    
    this.setState({robots: shuffle(this.state.robots)});
}

Don't forget to bind it in the constructor:

constructor() {
    super();
    this.state = {
      robots:[],
      selectedSeries: 'All'
    }

    this.selectSeries = this.selectSeries.bind(this);
+   this.sortShuffle  = this.sortShuffle.bind(this);
  }

Add a new button after the last Toggle button `

...

  <Toggle 
    text='5'
    clickHandler = {this.selectGameSerie}
    active = {currentGameSerie === '5'}
  />

  <Toggle
    className="abs-right"
    text='Shuffle'
    icon='random'
    clickHandler= {this.sortShuffle}
  />
</header>

Demo it!

Shows off the font-awesome!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment