Skip to content

Instantly share code, notes, and snippets.

@JoseGonzalez321
Last active September 29, 2017 20:17
Show Gist options
  • Save JoseGonzalez321/e9556e97b5bb03070393bfbca90d54a9 to your computer and use it in GitHub Desktop.
Save JoseGonzalez321/e9556e97b5bb03070393bfbca90d54a9 to your computer and use it in GitHub Desktop.
Steps for Robot Masters Demo
  • You may wanna do a npm install before the talk starts. It's a lot of dead time...and you know WIFI issues.

  • Remove everything inside `render()

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, i) =>{
          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(json => {
      this.setState({robots: json});
    })
}

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} alt={robot.name} />
        {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} alt={robot.name} />
    {robot.name} - {robot.weakness}
</li>

Before return(), add

const { id, name, avatar, weakness } = 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 { id, name, avatar, weakness } = props;
    return (
        <li>
          <img height="40" width="40" src={avatar} alt={name} />
          {name} - {weapon}
        </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>       
        How many I got: {robots.length}

        <ul>
        {robots.map((robot, i) => {
          return (
            <RobotMaster key={robot.id} {...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='robot-mug'>
    <img src={avatar} alt={name}/>
    <div className='robot-name'>{name}</div>
    <div className='robot-serial'>Serial: {id}</div>
</div>  

Add the weakness and image sprite sections

<div className="robot-info">  
    <h3 className="robot-weakness">Weakness</h3>
    <div>{weapon}</div>
</div>
<div className="robot-other">
    <img className="img-sprite" alt={name} src={sprite1} />
</div>

Note: You probably need sprite1 to the deconstruction section:

const { id, name, avatar, weapon, sprite1 } = props;

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

Final result:

<li className={listClass}>
    <div className="robot-mug">
        <img src={avatar} alt={name}/>
        <div className='robot-name'>{name}</div>
        <div className='robot-serial'>Serial: {id}</div>
    </div>     
    <div className="robot-info">  
        <h3 className="robot-weapon">Weapon</h3>
        <div>{weapon}</div>
    </div>
    <div className="robot-other">
        <img className="img-sprite" alt={name} src={sprite1} />
    </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, icon, active, 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'>

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

<div className='abs-left'>
    <Toggle
        text='All'
        clickHandler = {this.selectSeries}
    />
    <Toggle
        text='2'
        clickHandler = {this.selectSeries}
    />
    <Toggle
        text='3'
        clickHandler = {this.selectSeries}
    />
</div>

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

Add a new method called selectSeries

selectSeries(e) {
    if (this.state.selectedSeries === e.target.textContent) return;

    this.setState({selectedSeries: 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 {selectedSeries} = this.state;

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

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

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

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

+    this.selectSeries = this.selectSeries.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.selectedSeries !== prevState.selectedSeries) {
      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 = {selectedSeries === 'All'} to each Toggle button to toggle their active state.

<div className='abs-left'>
    <Toggle
    text='All'
+   active = {selectedSeries === 'All'}
    clickHandler = {this.selectSeries}
    />
    <Toggle
    text='2'
+   active = {selectedSeries === '2'}
    clickHandler = {this.selectSeries}
    />
    <Toggle
    text='3'
+   active = {selectedSeries === '3'}
    clickHandler = {this.selectSeries}
    />
</div>

Note: Do not forget to include selectedSeries in the desconstruction

const {robots, selectedSeries} = 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 key={robot.id} {...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 right before the <div style ={{padding: 15}} />

<div className="abs-right" style={{ height: 10}}>
    <Toggle 
        text='Shuffle'
        icon='random'
        clickHandler = {this.sortShuffle}
    />    
</div>

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