This repostory is contain every resources file that related to the session that happend University of colombo school of computing - 2018/04/25
workshop repo
- 'with-pure-js' folder contain of small application that created using Vanilla Javascript.
- 'without-redux' this folder contain the team building app without using any state handling libs.
- 'with-redux' same application in above (2.) created using Redux
- VsCode Download
- Nodejs Download Node
- Git Download git
- create
index.html
, style.css and script.js file - then add style.css and script.js file into the html file.
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" type="text/css" href="./style.css">
<title>Team Build</title>
</head>
<body>
<div class="center-screen">
<input type="text" placeholder="Enter the character name">
<button class="btn" type="button">
<span>Add A Character</span>
</button>
<div class="results">
<ul></ul>
</div>
</div>
<script src="./script.js"></script>
</body>
</html>
- In the
script.js
get ref for input, button and ul tag by calling DOM and also addEventListener to the button.
var inputEl = document.querySelector('input');
var buttonEl = document.querySelector('button');
var ulEl = document.querySelector('ul');
buttonEl.addEventListener('click', addTeam);
- Then create two function for add and remove team members from the teams array
var teams = [];
function addTeam() {
var userInput = inputEl.value;
if (userInput.trim() == '') {
return;
}
var newTeam = { id: Math.random(), value: userInput };
teams.push(newTeam);
var teamLi = document.createElement('LI');
teamLi.textContent = userInput;
teamLi.addEventListener('click', removeTeam);
teamLi.dataset.id = newTeam.id;
ulEl.appendChild(teamLi);
console.log(teams);
}
function removeTeam(event) {
var clickedLi = event.target;
var itemId = clickedLi.dataset.id;
for (var i = 0; i < teams.length; i++) {
if (teams[i].id == itemId) {
teams.splice(i, 1);
break;
}
}
clickedLi.parentNode.removeChild(clickedLi);
console.log(teams);
}
- go and check style.css file in
with-pure-js
, if you need better style on the app.
- Install create-react-app globally
npm install -g create-react-app
- Create the app
create-react-app my-app-name
- go to the app
cd my-app-name
- Check if all the package are install otherwise install them by
npm install
- Start the application
npm start
Install git if you are not already instaled it
git init
setup gitgit remote add origin <REPO_URL>
add remotegit remote -v
check- get
git pull
git pull origin master
- add chnage to git
git add .
- commit the added chnages
git commit -m 'init'
- push local changers to remote
git push origin master
- remove existing
src
. - Create src folder on root, then create assets, components, styles, data, web-services and index.js in src file root
- add this code snipts to the index.js this will render your application to the root div and then run it through terminal by using
npm start
import React from 'react'
import ReactDOM from 'react-dom';
ReactDOM.render(<h1>Hellow</h1>, document.getElementById('root'))
- and then craete
style.css
in style folder,App.js
in components folder and crete api.js file isde of web-services folder - add this code snipts to
app.js
import React, { Component } from 'react'
import '../styles/index.css';
class App extends Component {
render(){
return(
<h1>Hellow</h1>
)
}
}
- add these css to the use style.css
body {
background-color: #1abc9c;
height: 100%;
}
.App {
text-align: center;
padding: 5%;
}
.right-button {
cursor: pointer;
float: right;
}
.list-item {
display: inline-block;
}
- now import
app.js
into the index.js
...
import App from './components/App';
ReactDOM.render(<App />, document.getElementById('root'));
-
now get the json file form resources folder and put it into the data folder that inside of src
-
lets get data with the delay , fot that import characters.json form data file into api.js and esport them.
import _characters from '../data/characters.json';
const TIMEOUT = 100;
const characters = (cb, timeout) => setTimeout(() => cb(_characters), timeout || TIMEOUT);
export default {
characters
}
- Befor get the characters from api we have to create varibale to store them, lest create state for that in
App.js
state = {
characters: [],
}
Now we can store characters data form api using setState
- lets get data into app.js using
componentDidMount
form react life-cycle, inside ofApp.js
import api from '../web-services/api';
....
componentDidMount() {
api.characters(characters => {
this.setState({ characters: characters })
})
}
.....
-
print the
this.state.characters
inside of the render method to see the data. -
lets fixd our view for put these data into 3 separeate sections. one for Character List other two for Hero List and Stats List
<div className="App">
<h2>Build Your Team</h2>
<div>
<div>
<h2>Character List</h2>
</div>
<div>
<h2>Hero List</h2>
</div>
<div>
<h4>Team Stats</h4>
</div>
</div>
</div>
- Lest Add bootstrap to your application goto the bootstrap web site and get the CDN link and then go to the public folder and add that link under head tag
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
- Lets add put the three section into cols
<div className="App">
<h2>Build Your Team</h2>
<div >
<div className="col-md-4">
<h2>Character List</h2>
</div>
<div className="col-md-4">
<h2>Hero List</h2>
</div>
<div className="col-md-4">
<h4>Team Stats</h4>
</div>
</div>
</div>
- Now load the Characters in to character list
...
<div className="col-md-4">
<h2>Character List</h2>
<ul className="list-group">
{
this.state.characters.map((character, i) => {
return (
<li key={character.id} class="list-group-item">
<div className="list-item">{character.name}</div>
</li>
)
})
}
</ul>
</div>
....
- Let's create function to add character into
hero
array using character id
...
state = {
characters: [],
heroes: []
}
...
addCharactersById(id, i) {
this.setState(prevState => ({
characters: this.state.characters.filter(function (character) {
return character.id !== id
}),
heroes: [...prevState.heroes, this.state.characters[i]]
}))
}
....
- lets create
onClick
on ui list div to calladdCharactersById
...
<li key={character.id} class="list-group-item">
<div className="list-item">{character.name}</div>
<div className="lsit-item right-button" onClick={() => this.addCharactersById(character.id, i)}> +
</div>
</li>
...
- add these heros into heros list
<div className="col-md-4">
<h2>Hero List</h2>
<ul className="list-group">
{
this.state.heroes.map((character, i) => {
return (
<li key={character.id} className="list-group-item">
<div className="list-item">{character.name}</div>
<div className="lsit-item right-button" onClick={() => this.removeHerosById(character.id, i)}>
x
</div>
</li>
)
})
}
</ul>
</div>
- Like we did with
addCharactersById
, lets remove heros form hero list usingremoveHerosById
function
removeHerosById(id, i) {
this.setState(prevState => ({
heroes: this.state.heroes.filter(function (character) {
return character.id !== id
}),
characters: [...prevState.characters, this.state.heroes[i]]
}))
}
- lets create 3 function for get stats data into stats list
...
strengthCalculate() {
let strength = 0;
this.state.heroes.forEach(hero => strength += hero.strength);
return strength
}
intelligenceCalculate() {
let intelligence = 0;
this.state.heroes.forEach(hero => intelligence += hero.intelligence);
return intelligence
}
speedCalculate() {
let speed = 0;
this.state.heroes.forEach(hero => speed += hero.speed);
return speed
}
...
- Lets bind them with html
...
<div className="col-md-4">
<h4>Team Stats</h4>
<ul className="list-group">
<li className="list-group-item">
<b>Overall Strength:</b> {this.strengthCalculate()}
</li>
<li className="list-group-item">
<b>Overall Intelligence:</b> {this.intelligenceCalculate()}
</li>
<li className="list-group-item">
<b>Overall Speed:</b> {this.speedCalculate()}
</li>
</ul>
</div>
...
npm install --save redux react-redux
- Add Redux folders to the 'app/src'
mkdir reducers data actions
- And then add
characters.json
into a data folder
- create
index.js
inside of the reducers folder - import data
import _characters from '../data/characters.json';
- the create first reducer function for characters
function characters(state = _characters, action) {
switch (action.type) {
default:
return state;
}
}
export default characters;
-
Go to the root of the render method of Dom
-
Access the rootReducer by importing
import rootReducers from './reducers'
-
import { Provider } from 'react-redux';
Importing Provider we can use . is the higher-order component provided by React Redux that lets you bind Redux to React (see Usage with React). -
Then import createStore for create a store
import { createStore } from 'redux';
-
const store = createStore(rootReducers);
-
Wrap the provider around the App
<Provider store={store}>
<App />
</Provider>
- check the whole state by calling initial state of the store
console.log('store.getState() ', store.getState());
- Go to actions and create a
index.js
- Create action constant
export const ADD_CHARACTOR = 'ADD_CHARACTOR';
- export acction by setting type and data
export function addCharacterById(id) {
const action = {
type: ADD_CHARACTOR,
id
}
return action;
}
- import action to reducer
import { ADD_CHARACTOR } from '../actions'
- update reducer
function characters(state = _characters, action) {
switch (action.type) {
case ADD_CHARACTOR:
let characters = state.filter(item => item.id !== action.id);
return characters;
default:
return state;
}
}
- To catch every changes in store lets add subscribe to it
store.subscribe(() => console.log('store ', store.getState()))
- Lets tell store to Dispatch one action
store.dispatch(addCharacterById(2))
- update reducer
function heroes(state= [], action){
switch (action.type) {
case ADD_CHARACTOR:
default:
return state;
}
}
- For create cracter we going to create helper function
function createCharacter(id) {
let character = _characters.find(c => c.id === id);
return character;
}
- Then add that to heroes
function heroes(state= [], action){
switch (action.type) {
case ADD_CHARACTOR:
let heroes = [...state, createCharacter(action.id)]
return heroes;
default:
return state;
}
}
- Now we have to bind these two reducers, For that we can use combineReducers form redux
import { combineReducers } from 'redux';
- export the root reducer by binding them
const rootReducer = combineReducers({
characters,
heroes
});
export default rootReducer;
- If you neeed this in more structural way you can separet reducers by thire uniqueness
- Create Separate Component in Components
CharacterList.js
- Export it and add that to App.js
import CharacterList from './CharacterList';
import React, { Component } from 'react'
class CharacterList extends Component {
render() {
return (
<div>
<h2>Character List</h2>
</div>
)
}
}
export default CharacterList;
- Connect with redux first add connect from react-redux
import { connect } from 'react-redux';
...
export default connect()(CharacterList);
- Map State to props
...
function mapStateToProps(state) {
return {
characters: state.characters
};
}
export default connect(mapStateToProps, null)(CharacterList);
- For that we have to first bind action by importing
import { bindActionCreators } from 'redux';
- And also we have to get the function from actiomn by importing
import { addCharacterById } from '../actions';
- Now bind them connect with component
function mapDispatchToProps(dispatch){
return bindActionCreators({addCharacterById}, dispatch)
}
export default connect(mapStateToProps, mapDispatchToProps)(CharacterList);
- For check it lets call it from them component
...
{
this.props.characters.map((character, i) => {
return (
<li key={character.id} className="list-group-item">
<div className="list-item">{character.name}</div>
<div className="lsit-item right-button" onClick={() => this.props.addCharacterById(character.id, i)}> +
</div>
</li>
)
})
}
...
- check the props is comming properly by adding console.log inside render
console.log('this.props ', this.props)
- short cut, remove mapDispatchToProps from connect and directly add addCharacterById as a object
- Add new acction const
export const REMOVE_CHARACTOR = 'REMOVE_CHARACTOR';
- Lets add remove characters function
export function removeCharacterById(id) {
const action = {
type: REMOVE_CHARACTOR,
id
}
return action;
}
- add const to heroes
import { ADD_CHARACTOR, REMOVE_CHARACTOR } from '../actions'
- add new remove case type to heroes function
...
case REMOVE_CHARACTOR:
heroes = state.filter(item => item.id !== action.id)
return heroes;
...
- new create add characters case again to
characters_reducer.js
case REMOVE_CHARACTOR:
characters = [...state, createCharacter(action.id)]
return characters;
- thn connect with HeroList component like we did before!