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>
)
}
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 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;
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>
)
}
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>
);
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>
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>
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();
}
}
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!
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.
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>
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!