├── 01-react-tryout
└── index.html
├── 02-environment-setup
└── webpack
│ ├── .gitignore
│ ├── README.md
│ ├── node_modules
│ └── .gitignore
│ ├── package.json
│ ├── public
│ └── index.html
│ ├── src
│ ├── components
│ │ └── App.js
│ └── index.js
│ └── webpack.config.js
├── 03-jsx
├── .gitignore
├── .jshintrc
├── .tern-project
├── README.md
├── index.html
├── node_modules
│ └── .gitignore
├── package.json
├── src
│ └── App.js
└── webpack.config.js
├── 04-component
├── .gitignore
├── .jshintrc
├── README.md
├── node_modules
│ └── .gitignore
├── package.json
├── public
│ └── index.html
├── src
│ ├── components
│ │ ├── App.js
│ │ ├── Content.js
│ │ └── Header.js
│ └── index.js
└── webpack.config.js
├── 05-state-and-props
├── .gitignore
├── .jshintrc
├── README.md
├── node_modules
│ └── .gitignore
├── package.json
├── public
│ └── index.html
├── src
│ ├── components
│ │ ├── App.js
│ │ ├── Content.js
│ │ ├── Header.js
│ │ ├── RandomNumber.js
│ │ └── StateExample.js
│ └── index.js
└── webpack.config.js
├── 06-component-iteration
├── .gitignore
├── .jshintrc
├── README.md
├── index.html
├── node_modules
│ └── .gitignore
├── package.json
├── preview.png
├── src
│ └── App.js
└── webpack.config.js
├── 09-router
├── .gitignore
├── README.md
├── index.html
├── node_modules
│ └── .gitignore
├── package.json
├── src
│ └── App.js
└── webpack.config.js
├── 10-redux
├── .gitignore
├── README.md
├── index.html
├── package.json
├── src
│ ├── actions
│ │ └── index.js
│ ├── components
│ │ ├── App.js
│ │ ├── Buttons.js
│ │ ├── Counter.js
│ │ └── Option.js
│ ├── index.js
│ ├── index_without_reactredux.js
│ └── reducers
│ │ └── index.js
└── webpack.config.js
├── 11-using-express-hmr
├── .babelrc
├── .gitignore
├── README.md
├── package.json
├── public
│ └── index.html
├── server
│ ├── main.js
│ └── routes
│ │ └── posts.js
├── src
│ ├── App.js
│ └── index.js
├── webpack.config.js
└── webpack.dev.config.js
└── README.md
/01-react-tryout/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | React Tutorial
7 |
8 |
9 |
10 |
11 |
12 |
13 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/02-environment-setup/webpack/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/*/
2 | .jshintrc
3 |
--------------------------------------------------------------------------------
/02-environment-setup/webpack/README.md:
--------------------------------------------------------------------------------
1 | # REACT.JS ENVIRONMENT SETUP - WEBPACK
2 |
3 | Link to blog post - (KOREAN) [[React JS] 강좌 2편 작업환경 설정하기](http://velopert.com/814)
4 |
5 | This project uses React 0.14.7, Babel 6 and Webpack to setup the development
6 | environment for React.js on NodeJS
7 |
8 | ## How to install
9 | - Run ``npm install`` to install the dependency
10 | - Run ``npm start`` to run the development server
11 |
12 |
13 | *Server port is set to **7777***
14 |
--------------------------------------------------------------------------------
/02-environment-setup/webpack/node_modules/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/velopert/react-tutorials/ad4304541bad5c9ba6cd12338aedf4d86970857f/02-environment-setup/webpack/node_modules/.gitignore
--------------------------------------------------------------------------------
/02-environment-setup/webpack/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react_tutorial",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "./node_modules/.bin/webpack-dev-server --hot --host 0.0.0.0"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "react": "^0.14.7",
13 | "react-dom": "^0.14.7"
14 | },
15 | "devDependencies": {
16 | "babel-core": "^6.7.0",
17 | "babel-loader": "^6.2.4",
18 | "babel-preset-es2015": "^6.6.0",
19 | "babel-preset-react": "^6.5.0",
20 | "webpack": "^1.12.14",
21 | "webpack-dev-server": "^1.14.1"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/02-environment-setup/webpack/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | React App
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/02-environment-setup/webpack/src/components/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | class App extends React.Component {
4 | render(){
5 |
6 | return (
7 | Hello Velopert
8 | );
9 | }
10 | }
11 |
12 | export default App;
13 |
--------------------------------------------------------------------------------
/02-environment-setup/webpack/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './components/App';
4 |
5 | const rootElement = document.getElementById('root');
6 | ReactDOM.render(, rootElement);
7 |
--------------------------------------------------------------------------------
/02-environment-setup/webpack/webpack.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | entry: './src/index.js',
3 |
4 | output: {
5 | path: __dirname + '/public',
6 | filename: 'bundle.js'
7 | },
8 |
9 | devServer: {
10 | inline: true,
11 | port: 7777,
12 | contentBase: __dirname + '/public'
13 | },
14 |
15 | module:
16 | {
17 | loaders: [
18 | {
19 | test: /\.js$/,
20 | loader: 'babel',
21 | exclude: /node_modules/,
22 | query: {
23 | cacheDirectory: true,
24 | presets: ['es2015', 'react']
25 | }
26 | }
27 | ]
28 | }
29 | };
30 |
--------------------------------------------------------------------------------
/03-jsx/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/*/
2 |
--------------------------------------------------------------------------------
/03-jsx/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "exnext": true
3 | }
4 |
--------------------------------------------------------------------------------
/03-jsx/.tern-project:
--------------------------------------------------------------------------------
1 | {
2 | "ecmaVersion": 6,
3 | "libs": []
4 | }
5 |
--------------------------------------------------------------------------------
/03-jsx/README.md:
--------------------------------------------------------------------------------
1 | # REACT.JS JSX
2 |
3 |
--------------------------------------------------------------------------------
/03-jsx/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | React App
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/03-jsx/node_modules/.gitignore:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/03-jsx/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react_tutorial",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "./node_modules/.bin/webpack-dev-server --hot --host 0.0.0.0"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "react": "^0.14.7",
13 | "react-dom": "^0.14.7"
14 | },
15 | "devDependencies": {
16 | "babel-core": "^6.7.0",
17 | "babel-loader": "^6.2.4",
18 | "babel-preset-es2015": "^6.6.0",
19 | "babel-preset-react": "^6.5.0",
20 | "webpack": "^1.12.14",
21 | "webpack-dev-server": "^1.14.1"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/03-jsx/src/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 |
4 | class App extends React.Component {
5 | _sayHey(){
6 | alert("hey");
7 | }
8 |
9 | render(){
10 | let text = "Dev-Server";
11 |
12 | let pStyle = {
13 | color: 'aqua',
14 | backgroundColor: 'black'
15 | };
16 |
17 | return (
18 |
19 |
Hello Velopert
20 |
Welcome to {text}
21 |
22 |
{1 == 1 ? 'True' : 'False'}
23 |
24 | { /* COMMENT */ }
25 |
26 | );
27 | }
28 | }
29 |
30 | ReactDOM.render(, document.getElementById('app'));
31 |
--------------------------------------------------------------------------------
/03-jsx/webpack.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | entry: './src/App.js',
3 |
4 | output: {
5 | path: __dirname,
6 | filename: 'app.js'
7 | },
8 |
9 | devServer: {
10 | inline: true,
11 | port: 7777
12 | },
13 |
14 | module:
15 | {
16 | loaders: [
17 | {
18 | test: /\.js$/,
19 | loader: 'babel',
20 | exclude: /node_modules/,
21 | query: {
22 | cacheDirectory: true,
23 | presets: ['es2015', 'react']
24 | }
25 | }
26 | ]
27 | }
28 | };
29 |
--------------------------------------------------------------------------------
/04-component/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/*/
2 |
--------------------------------------------------------------------------------
/04-component/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "esversion": 6
3 | }
4 |
--------------------------------------------------------------------------------
/04-component/README.md:
--------------------------------------------------------------------------------
1 | # REACT.JS COMPONENT
2 |
--------------------------------------------------------------------------------
/04-component/node_modules/.gitignore:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/04-component/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react_tutorial",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "./node_modules/.bin/webpack-dev-server --hot --host 0.0.0.0"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "react": "^0.14.7",
13 | "react-dom": "^0.14.7"
14 | },
15 | "devDependencies": {
16 | "babel-core": "^6.7.0",
17 | "babel-loader": "^6.2.4",
18 | "babel-preset-es2015": "^6.6.0",
19 | "babel-preset-react": "^6.5.0",
20 | "webpack": "^1.12.14",
21 | "webpack-dev-server": "^1.14.1"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/04-component/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | React App
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/04-component/src/components/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Header from './Header';
3 | import Content from './Content';
4 |
5 | class App extends React.Component {
6 | render(){
7 | return (
8 |
9 |
10 |
11 |
12 | );
13 | }
14 | }
15 |
16 | export default App;
17 |
--------------------------------------------------------------------------------
/04-component/src/components/Content.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 |
4 | class Content extends React.Component {
5 | render(){
6 | return (
7 |
8 |
Content
9 |
Hey!
10 |
11 | );
12 | }
13 | }
14 |
15 | export default Content;
16 |
--------------------------------------------------------------------------------
/04-component/src/components/Header.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 |
4 | class Header extends React.Component {
5 | render(){
6 | return (
7 | Header
8 | );
9 | }
10 | }
11 |
12 | export default Header;
13 |
--------------------------------------------------------------------------------
/04-component/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './components/App'
4 |
5 | const rootElement = document.getElementById('root');
6 | ReactDOM.render(, rootElement);
7 |
--------------------------------------------------------------------------------
/04-component/webpack.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | entry: './src/index.js',
3 |
4 | output: {
5 | path: __dirname + '/public/',
6 | filename: 'bundle.js'
7 | },
8 |
9 | devServer: {
10 | inline: true,
11 | port: 7777,
12 | contentBase: __dirname + '/public/'
13 | },
14 |
15 | module:
16 | {
17 | loaders: [
18 | {
19 | test: /\.js$/,
20 | loader: 'babel',
21 | exclude: /node_modules/,
22 | query: {
23 | cacheDirectory: true,
24 | presets: ['es2015', 'react']
25 | }
26 | }
27 | ]
28 | }
29 | };
30 |
--------------------------------------------------------------------------------
/05-state-and-props/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/*/
2 |
--------------------------------------------------------------------------------
/05-state-and-props/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "esversion": 6
3 | }
4 |
--------------------------------------------------------------------------------
/05-state-and-props/README.md:
--------------------------------------------------------------------------------
1 | # REACT.JS COMPONENT
2 |
--------------------------------------------------------------------------------
/05-state-and-props/node_modules/.gitignore:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/05-state-and-props/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react_tutorial",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "./node_modules/.bin/webpack-dev-server --hot --host 0.0.0.0"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "react": "^0.14.7",
13 | "react-dom": "^0.14.7"
14 | },
15 | "devDependencies": {
16 | "babel-core": "^6.7.0",
17 | "babel-loader": "^6.2.4",
18 | "babel-preset-es2015": "^6.6.0",
19 | "babel-preset-react": "^6.5.0",
20 | "webpack": "^1.12.14",
21 | "webpack-dev-server": "^1.14.1"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/05-state-and-props/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | React App
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/05-state-and-props/src/components/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Header from './Header';
3 | import Content from './Content';
4 | import RandomNumber from './RandomNumber';
5 |
6 | class App extends React.Component {
7 |
8 | constructor(props){
9 | super(props);
10 |
11 | this.state = {
12 | value: Math.round(Math.random()*100)
13 | };
14 |
15 | this._updateValue = this._updateValue.bind(this);
16 | }
17 |
18 | render(){
19 | return (
20 |
21 |
27 | );
28 | }
29 |
30 | _updateValue(randomValue){
31 | this.setState({
32 | value: randomValue
33 | });
34 | }
35 | }
36 |
37 | App.defaultProps = {
38 | header: 'Default header',
39 | contentTitle: 'Default contentTitle',
40 | contentBody: 'Default contentBody'
41 | }
42 |
43 | export default App;
44 |
--------------------------------------------------------------------------------
/05-state-and-props/src/components/Content.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 |
4 | class Content extends React.Component {
5 | render(){
6 | return (
7 |
8 |
{ this.props.title }
9 |
{ this.props.body }
10 |
11 | );
12 | }
13 | }
14 |
15 | Content.propTypes = {
16 | title: React.PropTypes.string,
17 | body: React.PropTypes.string.isRequired
18 | };
19 |
20 | export default Content;
21 |
--------------------------------------------------------------------------------
/05-state-and-props/src/components/Header.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 |
4 | class Header extends React.Component {
5 | render(){
6 | return (
7 | { this.props.title }
8 | );
9 | }
10 | }
11 |
12 | export default Header;
13 |
--------------------------------------------------------------------------------
/05-state-and-props/src/components/RandomNumber.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 |
4 |
5 | class RandomNumber extends React.Component {
6 | _update(){
7 | let value = Math.round(Math.random()*100);
8 | this.props.onUpdate(value);
9 | }
10 |
11 | constructor(props){
12 | super(props);
13 | this._update = this._update.bind(this);
14 | }
15 |
16 | render(){
17 | return (
18 |
19 |
RANDOM NUMBER: { this.props.number }
20 |
21 |
22 | );
23 | }
24 | }
25 |
26 | export default RandomNumber;
27 |
--------------------------------------------------------------------------------
/05-state-and-props/src/components/StateExample.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | class StateExample extends React.Component {
4 | constructor(props) {
5 | super(props);
6 |
7 | this.state = {
8 | header: "Header Initial state",
9 | content: "Content Initial State"
10 | };
11 | }
12 |
13 | _updateHeader(text){
14 | this.setState({
15 | header: "Header has changed"
16 | });
17 | }
18 |
19 | render() {
20 | return (
21 |
22 |
{this.state.header}
23 | {this.state.content}
24 |
25 |
26 | );
27 | }
28 | }
29 |
30 | export default StateExample;
31 |
--------------------------------------------------------------------------------
/05-state-and-props/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './components/App'
4 |
5 | const rootElement = document.getElementById('root');
6 | ReactDOM.render(, rootElement);
7 |
--------------------------------------------------------------------------------
/05-state-and-props/webpack.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | entry: './src/index.js',
3 |
4 | output: {
5 | path: __dirname + '/public/',
6 | filename: 'bundle.js'
7 | },
8 |
9 | devServer: {
10 | inline: true,
11 | port: 7777,
12 | contentBase: __dirname + '/public/'
13 | },
14 |
15 | module:
16 | {
17 | loaders: [
18 | {
19 | test: /\.js$/,
20 | loader: 'babel',
21 | exclude: /node_modules/,
22 | query: {
23 | cacheDirectory: true,
24 | presets: ['es2015', 'react']
25 | }
26 | }
27 | ]
28 | }
29 | };
30 |
--------------------------------------------------------------------------------
/06-component-iteration/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/*/
2 |
--------------------------------------------------------------------------------
/06-component-iteration/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "esversion": 6
3 | }
4 |
--------------------------------------------------------------------------------
/06-component-iteration/README.md:
--------------------------------------------------------------------------------
1 | ## React Component Iteration thru Mapping & Using Immutability Helper
2 | Link to blog post - (KOREAN) [[React.JS] 강좌 6-2편 Immutability Helper – State 내부 Array 에 원소 삽입/제거/수정](https://velopert.com/1015)
3 |
4 | [](https://jsfiddle.net/velopert/k21ozagp/17/)
5 |
--------------------------------------------------------------------------------
/06-component-iteration/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | React App
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/06-component-iteration/node_modules/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/velopert/react-tutorials/ad4304541bad5c9ba6cd12338aedf4d86970857f/06-component-iteration/node_modules/.gitignore
--------------------------------------------------------------------------------
/06-component-iteration/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react_tutorial",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "./node_modules/.bin/webpack-dev-server --hot --host 0.0.0.0"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "react": "^0.14.7",
13 | "react-addons-update": "^0.14.7",
14 | "react-dom": "^0.14.7"
15 | },
16 | "devDependencies": {
17 | "babel-core": "^6.7.0",
18 | "babel-loader": "^6.2.4",
19 | "babel-preset-es2015": "^6.6.0",
20 | "babel-preset-react": "^6.5.0",
21 | "webpack": "^1.12.14",
22 | "webpack-dev-server": "^1.14.1"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/06-component-iteration/preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/velopert/react-tutorials/ad4304541bad5c9ba6cd12338aedf4d86970857f/06-component-iteration/preview.png
--------------------------------------------------------------------------------
/06-component-iteration/src/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import update from 'react-addons-update';
4 |
5 | class App extends React.Component {
6 | render(){
7 |
8 | return (
9 |
10 | );
11 | }
12 | }
13 |
14 | class Contacts extends React.Component {
15 | constructor(props) {
16 | super(props);
17 | this.state = {
18 | contactData: [
19 | {name: "Abet", phone: "010-0000-0001"},
20 | {name: "Betty", phone: "010-0000-0002"},
21 | {name: "Charlie", phone: "010-0000-0003"},
22 | {name: "David", phone: "010-0000-0004"}
23 | ],
24 | selectedKey: -1,
25 | selected: {
26 | name: "",
27 | phone: ""
28 | }
29 | };
30 | }
31 |
32 | _insertContact(name, phone){
33 | let newState = update(this.state, {
34 | contactData: {
35 | $push: [{"name": name, "phone": phone}]
36 | }
37 | });
38 | this.setState(newState);
39 | }
40 |
41 |
42 | _onSelect(key){
43 | if(key==this.state.selectedKey){
44 | console.log("key select cancelled");
45 | this.setState({
46 | selectedKey: -1,
47 | selected: {
48 | name: "",
49 | phone: ""
50 | }
51 | });
52 | return;
53 | }
54 |
55 | this.setState({
56 | selectedKey: key,
57 | selected: this.state.contactData[key]
58 | });
59 | console.log(key + " is selected");
60 | }
61 |
62 | _isSelected(key){
63 | if(this.state.selectedKey == key){
64 | return true;
65 | }else{
66 | return false;
67 | }
68 | }
69 |
70 | _removeContact(){
71 | if(this.state.selectedKey==-1){
72 | console.log("contact not selected");
73 | return;
74 | }
75 |
76 | this.setState({
77 | contactData: update(
78 | this.state.contactData,
79 | {
80 | $splice: [[this.state.selectedKey, 1]]
81 | }
82 | ),
83 | selectedKey: -1
84 | });
85 | }
86 |
87 | _editContact(name, phone){
88 | this.setState({
89 | contactData: update(
90 | this.state.contactData,
91 | {
92 | [this.state.selectedKey]: {
93 | name: { $set: name },
94 | phone: { $set: phone }
95 | }
96 | }
97 | ),
98 | selected: {
99 | name: name,
100 | phone: phone
101 | }
102 | });
103 | }
104 |
105 |
106 |
107 | render(){
108 | return(
109 |
110 |
Contacts
111 |
112 | {this.state.contactData.map((contact, i) => {
113 | return ();
119 | })}
120 |
121 |
122 |
123 |
126 |
127 | );
128 | }
129 | }
130 |
131 |
132 | class ContactInfo extends React.Component {
133 |
134 | handleClick(){
135 | this.props.onSelect(this.props.contactKey);
136 | }
137 |
138 | shouldComponentUpdate(nextProps, nextState){
139 | return (JSON.stringify(nextProps) != JSON.stringify(this.props));
140 | }
141 |
142 | render() {
143 | console.log("rendered: " + this.props.name);
144 |
145 | let getStyle = isSelect => {
146 | if(!isSelect) return;
147 |
148 | let style = {
149 | fontWeight: 'bold',
150 | backgroundColor: '#4efcd8'
151 | };
152 |
153 | return style;
154 | };
155 |
156 | return(
157 |
159 | {this.props.name} {this.props.phone}
160 |
161 | );
162 | }
163 | }
164 |
165 | class ContactCreator extends React.Component {
166 | constructor(props) {
167 | super(constructor);
168 | // Configure default state
169 | this.state = {
170 | name: "",
171 | phone: ""
172 | };
173 | }
174 |
175 | handleClick(){
176 | this.props.onInsert(this.state.name, this.state.phone);
177 | this.setState({
178 | name: "",
179 | phone: ""
180 | });
181 | }
182 |
183 | handleChange(e){
184 | var nextState = {};
185 | nextState[e.target.name] = e.target.value;
186 | this.setState(nextState);
187 | }
188 |
189 | render() {
190 | return (
191 |
209 | );
210 | }
211 | }
212 |
213 | class ContactRemover extends React.Component {
214 | handleClick() {
215 | this.props.onRemove();
216 | }
217 |
218 | render() {
219 | return (
220 |
223 | );
224 | }
225 | }
226 |
227 | class ContactEditor extends React.Component {
228 | constructor(props) {
229 | super(constructor);
230 | // Configure default state
231 | this.state = {
232 | name: "",
233 | phone: ""
234 | };
235 | }
236 |
237 | handleClick(){
238 | if(!this.props.isSelected){
239 | console.log("contact not selected");
240 |
241 | return;
242 | }
243 |
244 | this.props.onEdit(this.state.name, this.state.phone);
245 | }
246 |
247 | handleChange(e){
248 | var nextState = {};
249 | nextState[e.target.name] = e.target.value;
250 | this.setState(nextState);
251 | }
252 |
253 | componentWillReceiveProps(nextProps){
254 | this.setState({
255 | name: nextProps.contact.name,
256 | phone: nextProps.contact.phone
257 | });
258 | }
259 |
260 | render() {
261 | return (
262 |
280 | );
281 | }
282 | }
283 |
284 | ReactDOM.render(, document.getElementById('app'));
285 |
--------------------------------------------------------------------------------
/06-component-iteration/webpack.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | entry: './src/App.js',
3 |
4 | output: {
5 | path: __dirname,
6 | filename: 'app.js'
7 | },
8 |
9 | devServer: {
10 | inline: true,
11 | port: 7777
12 | },
13 |
14 | module:
15 | {
16 | loaders: [
17 | {
18 | test: /\.js$/,
19 | loader: 'babel',
20 | exclude: /node_modules/,
21 | query: {
22 | cacheDirectory: true,
23 | presets: ['es2015', 'react']
24 | }
25 | }
26 | ]
27 | }
28 | };
29 |
--------------------------------------------------------------------------------
/09-router/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/*/
2 | .jshintrc
3 | ./app.js
4 |
--------------------------------------------------------------------------------
/09-router/README.md:
--------------------------------------------------------------------------------
1 | # REACT.JS TUTORIAL - ROUTER
2 |
--------------------------------------------------------------------------------
/09-router/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | React App
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/09-router/node_modules/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/velopert/react-tutorials/ad4304541bad5c9ba6cd12338aedf4d86970857f/09-router/node_modules/.gitignore
--------------------------------------------------------------------------------
/09-router/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react_tutorial",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "./node_modules/.bin/webpack-dev-server --hot --host 0.0.0.0"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "react": "^0.14.7",
13 | "react-dom": "^0.14.7",
14 | "react-router": "^2.0.1"
15 | },
16 | "devDependencies": {
17 | "babel-core": "^6.7.0",
18 | "babel-loader": "^6.2.4",
19 | "babel-preset-es2015": "^6.6.0",
20 | "babel-preset-react": "^6.5.0",
21 | "webpack": "^1.12.14",
22 | "webpack-dev-server": "^1.14.1"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/09-router/src/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import { Router, Route, Link, browserHistory, IndexRoute} from 'react-router';
4 |
5 |
6 | class App extends React.Component {
7 | render() {
8 |
9 | return (
10 |
11 |
12 | - Home
13 | - About
14 | - Articles
15 |
16 | {this.props.children}
17 |
18 | );
19 | }
20 | }
21 |
22 | class Home extends React.Component {
23 | render() {
24 | return (
25 | Hey, I am HOME!
26 | );
27 | }
28 | }
29 |
30 | class About extends React.Component {
31 | render() {
32 | return (
33 | Hey, I am ABOUT!
34 | );
35 | }
36 | }
37 |
38 | class Articles extends React.Component {
39 | render() {
40 | return (
41 | Hey, I am ARTCILES!
42 | );
43 | }
44 | }
45 |
46 | ReactDOM.render(
47 |
48 |
49 |
50 |
51 |
52 |
53 | , document.getElementById('app'));
54 |
--------------------------------------------------------------------------------
/09-router/webpack.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | entry: './src/App.js',
3 |
4 | output: {
5 | path: __dirname,
6 | filename: 'app.js'
7 | },
8 |
9 | devServer: {
10 | inline: true,
11 | port: 7777,
12 | historyApiFallback: true
13 | },
14 |
15 | module:
16 | {
17 | loaders: [
18 | {
19 | test: /\.js$/,
20 | loader: 'babel',
21 | exclude: /node_modules/,
22 | query: {
23 | cacheDirectory: true,
24 | presets: ['es2015', 'react']
25 | }
26 | }
27 | ]
28 | }
29 | };
30 |
--------------------------------------------------------------------------------
/10-redux/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/*/
2 | .jshintrc
3 | ./app.js
4 |
--------------------------------------------------------------------------------
/10-redux/README.md:
--------------------------------------------------------------------------------
1 | # 10. redux
2 |
--------------------------------------------------------------------------------
/10-redux/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | React App
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/10-redux/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react_tutorial",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "./node_modules/.bin/webpack-dev-server --hot --host 0.0.0.0"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "react": "^0.14.7",
13 | "react-dom": "^0.14.7",
14 | "react-redux": "^4.4.5",
15 | "redux": "^3.5.1"
16 | },
17 | "devDependencies": {
18 | "babel-core": "^6.7.0",
19 | "babel-loader": "^6.2.4",
20 | "babel-preset-es2015": "^6.6.0",
21 | "babel-preset-react": "^6.5.0",
22 | "webpack": "^1.12.14",
23 | "webpack-dev-server": "^1.14.1"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/10-redux/src/actions/index.js:
--------------------------------------------------------------------------------
1 | export const INCREMENT = 'INCREMENT';
2 | export const DECREMENT = 'DECREMENT';
3 | export const SET_DIFF = 'SET_DIFF';
4 |
5 | export function increment() {
6 | return {
7 | type: INCREMENT
8 | };
9 | }
10 |
11 | export function decrement() {
12 | return {
13 | type: DECREMENT
14 | };
15 | }
16 |
17 | export function setDiff(value) {
18 | return {
19 | type: SET_DIFF,
20 | diff: value
21 | };
22 | }
23 |
--------------------------------------------------------------------------------
/10-redux/src/components/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Counter from './Counter';
3 | import Buttons from './Buttons';
4 | import Option from './Option';
5 |
6 | class App extends React.Component {
7 | render(){
8 | return (
9 |
10 |
11 |
12 |
13 |
14 | );
15 | }
16 |
17 | }
18 |
19 | export default App;
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/10-redux/src/components/Buttons.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { connect } from 'react-redux';
3 | import { increment, decrement } from '../actions';
4 |
5 | class Buttons extends React.Component {
6 | render() {
7 | return (
8 |
9 |
13 |
17 |
18 | )
19 | }
20 | }
21 |
22 |
23 | let mapDispatchToProps = (dispatch) => {
24 | return {
25 | onIncrement: () => dispatch(increment()),
26 | onDecrement: () => dispatch(decrement())
27 | }
28 | }
29 |
30 | Buttons = connect(undefined, mapDispatchToProps)(Buttons);
31 |
32 | export default Buttons;
33 |
--------------------------------------------------------------------------------
/10-redux/src/components/Counter.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { connect } from 'react-redux';
3 |
4 | class Counter extends React.Component {
5 | render() {
6 | return (
7 | VALUE: { this.props.value }
8 | );
9 | }
10 | }
11 |
12 | let mapStateToProps = (state) => {
13 | return {
14 | value: state.counter.value
15 | };
16 | }
17 |
18 | Counter = connect(mapStateToProps)(Counter);
19 |
20 | export default Counter;
21 |
--------------------------------------------------------------------------------
/10-redux/src/components/Option.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { connect } from 'react-redux';
3 | import { setDiff } from '../actions';
4 |
5 | class Option extends React.Component {
6 | constructor(props) {
7 | super(props);
8 |
9 | this.state = {
10 | diff: '1'
11 | }
12 |
13 |
14 | this.onChangeDiff = this.onChangeDiff.bind(this);
15 | }
16 |
17 | render() {
18 | return (
19 |
20 |
21 |
22 | );
23 | }
24 |
25 | onChangeDiff(e) {
26 |
27 | if(isNaN(e.target.value))
28 | return;
29 |
30 | this.setState({ diff: e.target.value });
31 |
32 | if(e.target.value=='') {
33 | this.setState({ diff: '0' });
34 | }
35 |
36 | this.props.onUpdateDiff(parseInt(e.target.value));
37 |
38 | }
39 | }
40 |
41 | let mapDispatchToProps = (dispatch) => {
42 | return {
43 | onUpdateDiff: (value) => dispatch(setDiff(value))
44 | };
45 | }
46 |
47 | Option = connect(undefined, mapDispatchToProps)(Option);
48 |
49 | export default Option;
50 |
--------------------------------------------------------------------------------
/10-redux/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import { createStore } from 'redux';
4 | import { Provider } from 'react-redux';
5 | import App from './components/App';
6 | import counterApp from './reducers';
7 |
8 | const store = createStore(counterApp);
9 | const appElement = document.getElementById('app');
10 |
11 |
12 |
13 | ReactDOM.render(
14 |
15 |
16 | ,
17 | appElement
18 | );
19 |
--------------------------------------------------------------------------------
/10-redux/src/index_without_reactredux.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import { createStore } from 'redux';
4 |
5 |
6 | /*
7 | * Action
8 | */
9 | const INCREMENT = "INCREMENT";
10 |
11 | function increase(diff) {
12 | return {
13 | type: INCREMENT,
14 | addBy: diff
15 | };
16 | }
17 |
18 |
19 | /*
20 | * Reducer
21 | */
22 | const initialState = {
23 | value: 0
24 | };
25 |
26 | const counterReducer = (state = initialState, action) => {
27 | switch(action.type) {
28 | case INCREMENT:
29 | return Object.assign({}, state, {
30 | value: state.value + action.addBy
31 | });
32 | default:
33 | return state;
34 | }
35 | }
36 |
37 |
38 |
39 | /*
40 | * Store
41 | */
42 | const store = createStore(counterReducer);
43 |
44 | /*
45 | * App Component
46 | */
47 | class App extends React.Component {
48 | constructor(props) {
49 | super(props);
50 | this.onClick = this.onClick.bind(this);
51 | }
52 |
53 | render() {
54 |
55 | let centerStyle = {
56 | position: 'fixed',
57 | top: '50%',
58 | left: '50%',
59 | transform: 'translate(-50%, -50%)',
60 | WebkitUserSelect: 'none',
61 | MozUserSelect: 'none',
62 | MsUserSelect:'none',
63 | userSelect: 'none',
64 | cursor: 'pointer'
65 | };
66 |
67 | return (
68 |
72 |
73 |
{this.props.store.getState().value}
74 |
75 | )
76 | }
77 |
78 | onClick() {
79 | this.props.store.dispatch(increase(1));
80 | }
81 | }
82 |
83 | /*
84 | * Rendering
85 | */
86 | const render = () => {
87 |
88 | const appElement = document.getElementById('app');
89 | ReactDOM.render(
90 | ,
91 | appElement
92 | );
93 | };
94 |
95 | store.subscribe(render);
96 | render();
97 |
--------------------------------------------------------------------------------
/10-redux/src/reducers/index.js:
--------------------------------------------------------------------------------
1 | import { INCREMENT, DECREMENT, SET_DIFF } from '../actions';
2 | import { combineReducers } from 'redux';
3 |
4 | const counterInitialState = {
5 | value: 0,
6 | diff: 1
7 | };
8 |
9 | const counter = (state = counterInitialState, action) => {
10 | switch(action.type) {
11 | case INCREMENT:
12 | return Object.assign({}, state, {
13 | value: state.value + state.diff
14 | });
15 | case DECREMENT:
16 | return Object.assign({}, state, {
17 | value: state.value - state.diff
18 | });
19 | case SET_DIFF:
20 | return Object.assign({}, state, {
21 | diff: action.diff
22 | });
23 | default:
24 | return state;
25 | }
26 | };
27 |
28 |
29 | const extra = (state = { value: 'this_is_extra_reducer' }, action) => {
30 | switch(action.type) {
31 | default:
32 | return state;
33 | }
34 | }
35 |
36 | const counterApp = combineReducers({
37 | counter,
38 | extra
39 | });
40 |
41 | export default counterApp;
42 |
--------------------------------------------------------------------------------
/10-redux/webpack.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | entry: './src/index.js',
3 |
4 | output: {
5 | path: __dirname,
6 | filename: 'app.js'
7 | },
8 |
9 | devServer: {
10 | inline: true,
11 | port: 7777
12 | },
13 |
14 | module:
15 | {
16 | loaders: [
17 | {
18 | test: /\.js$/,
19 | loader: 'babel',
20 | exclude: /node_modules/,
21 | query: {
22 | cacheDirectory: true,
23 | presets: ['es2015', 'react']
24 | }
25 | }
26 | ]
27 | }
28 | };
29 |
--------------------------------------------------------------------------------
/11-using-express-hmr/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015"]
3 | }
4 |
--------------------------------------------------------------------------------
/11-using-express-hmr/.gitignore:
--------------------------------------------------------------------------------
1 | public/bundle.js
2 | node_modules/**
3 | build/**
4 |
--------------------------------------------------------------------------------
/11-using-express-hmr/README.md:
--------------------------------------------------------------------------------
1 | # React-Express-HMR-Example
2 |
3 | ## About
4 | This is an example project that uses React.js on Express.js server. In development environment, webpack-dev-server will be launched together with Express.js server that has Hot Module Replacement enabled using react-hot-loader.
5 | Both of client-side and server-side codes are written in ES6 syntax.
6 |
7 | The port of Express.js server is 3000 and port of webpack-dev-server is 3001.
8 |
9 | ## Installation
10 | ```
11 | npm install
12 | ```
13 |
14 | ## Scripts
15 | ### clean
16 | ```bash
17 | # removes build directory and bundle.js
18 | npm run clean
19 | ```
20 | ### build
21 | ```bash
22 | # transpiles ES6 codes of both client-side and server-side
23 | npm run build
24 | ```
25 | ### start
26 | ```bash
27 | # starts the server with production environment
28 | npm run start
29 | ```
30 | ### development
31 | ```bash
32 | # starts the server with development environment
33 | npm run development
34 | ```
35 |
--------------------------------------------------------------------------------
/11-using-express-hmr/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-express-hmr",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "clean": "rm -rf build public/bundle.js",
8 | "build": "./node_modules/.bin/babel server --out-dir build && ./node_modules/.bin/webpack",
9 | "start": "NODE_ENV=production node ./build/main.js",
10 | "development": "NODE_ENV=development node ./build/main.js"
11 | },
12 | "author": "velopert (https://velopert.com)",
13 | "license": "ISC",
14 | "dependencies": {
15 | "express": "^4.13.4",
16 | "react": "^15.0.2",
17 | "react-dom": "^15.0.2"
18 | },
19 | "devDependencies": {
20 | "babel-cli": "^6.9.0",
21 | "babel-core": "^6.8.0",
22 | "babel-loader": "^6.2.4",
23 | "babel-preset-es2015": "^6.6.0",
24 | "babel-preset-react": "^6.5.0",
25 | "react-hot-loader": "^1.3.0",
26 | "webpack": "^1.13.0",
27 | "webpack-dev-server": "^1.14.1"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/11-using-express-hmr/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | React App on Express Server
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/11-using-express-hmr/server/main.js:
--------------------------------------------------------------------------------
1 | import express from 'express';
2 | import WebpackDevServer from 'webpack-dev-server';
3 | import webpack from 'webpack';
4 |
5 | const app = express();
6 | const port = 3000;
7 | const devPort = 3001;
8 |
9 |
10 | if(process.env.NODE_ENV == 'development') {
11 | console.log('Server is running on development mode');
12 |
13 | const config = require('../webpack.dev.config');
14 | let compiler = webpack(config);
15 | let devServer = new WebpackDevServer(compiler, config.devServer);
16 | devServer.listen(devPort, () => {
17 | console.log('webpack-dev-server is listening on port', devPort);
18 | });
19 | }
20 | app.use('/', express.static(__dirname + '/../public'));
21 |
22 | app.get('/hello', (req, res) => {
23 | return res.send('Can you hear me?');
24 | });
25 |
26 |
27 | import posts from './routes/posts';
28 | app.use('/posts', posts);
29 |
30 | const server = app.listen(port, () => {
31 | console.log('Express listening on port', port);
32 | });
33 |
--------------------------------------------------------------------------------
/11-using-express-hmr/server/routes/posts.js:
--------------------------------------------------------------------------------
1 | import express from 'express';
2 |
3 | const router = express.Router();
4 |
5 | router.get('/', (req,res) => {
6 | res.send('posts');
7 | });
8 |
9 | router.get('/read/:id', (req, res) => {
10 | res.send('You are reading post ' + req.params.id);
11 | });
12 |
13 | export default router;
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/11-using-express-hmr/src/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default class App extends React.Component {
4 | render() {
5 | return (
6 | This is Hot
7 | )
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/11-using-express-hmr/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 |
5 | let rootElement = document.getElementById('root');
6 |
7 | ReactDOM.render(, rootElement);
8 |
9 |
--------------------------------------------------------------------------------
/11-using-express-hmr/webpack.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 |
3 | entry: './src/index.js',
4 |
5 | output: {
6 | path: __dirname + '/public',
7 | filename: 'bundle.js'
8 | },
9 |
10 | module: {
11 | loaders: [
12 | {
13 | test: /\.js$/,
14 | loader: 'babel',
15 | exclude: /node_modules/,
16 | query: {
17 | cacheDirectory: true,
18 | presets: ['es2015', 'react']
19 | }
20 | }
21 | ]
22 | }
23 | };
24 |
--------------------------------------------------------------------------------
/11-using-express-hmr/webpack.dev.config.js:
--------------------------------------------------------------------------------
1 | var webpack = require('webpack');
2 |
3 | module.exports = {
4 |
5 | entry: [
6 | './src/index.js',
7 | 'webpack-dev-server/client?http://0.0.0.0:3001',
8 | 'webpack/hot/only-dev-server'
9 | ],
10 |
11 | output: {
12 | path: '/',
13 | filename: 'bundle.js'
14 | },
15 |
16 | devServer: {
17 | hot: true,
18 | filename: 'bundle.js',
19 | publicPath: '/',
20 | historyApiFallback: true,
21 | contentBase: './public',
22 | proxy: {
23 | "*": "http://localhost:3000"
24 | }
25 | },
26 |
27 | plugins: [
28 | new webpack.optimize.OccurenceOrderPlugin(),
29 | new webpack.HotModuleReplacementPlugin(),
30 | new webpack.NoErrorsPlugin()
31 | ],
32 |
33 | module: {
34 | loaders: [
35 | {
36 | test: /\.js$/,
37 | loaders: ['react-hot', 'babel?' + JSON.stringify({
38 | cacheDirectory: true,
39 | presets: ['es2015', 'react']
40 | })],
41 | exclude: /node_modules/,
42 | }
43 | ]
44 | }
45 | };
46 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | M# REACT TUTORIALS
2 |
3 | This repository has some sample ReactJS projects that are used from the tutorials in [Velopert Blog](http://velopert.com) (KOREAN)
4 |
5 |
6 | | Directory | Blog Post |
7 | | ------------- |-------------|
8 | | 01-react-tryout| [[React.JS] 강좌 1편 소개 및 맛보기](https://velopert.com/775) |
9 | | 02-environment-setup | [[React.JS] 강좌 2편 작업환경 설정하기](https://velopert.com/814)|
10 | | 03-jsx| [[React.JS] 강좌 3편 JSX](https://velopert.com/867)|
11 | | 04-component | [[React.JS] 강좌 4편 Component 생성 및 모듈화](http://velopert.com/900)|
12 |
13 | # .
14 |
--------------------------------------------------------------------------------