├── app ├── src │ ├── components │ │ ├── category-row.jsx │ │ ├── product-row.jsx │ │ ├── product-table.jsx │ │ └── search-bar.jsx │ ├── models │ │ └── products.jsx │ └── filterable-product-table.jsx ├── stylesheets │ └── main.css └── main.jsx ├── .travis.yml ├── README.md ├── webpack.config.js ├── .gitignore └── package.json /app/src/components/category-row.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default ({category}) => ( 4 | 5 | {category} 6 | 7 | ); -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '0.10' 4 | - '5.3' 5 | - '6' 6 | matrix: 7 | allow_failures: 8 | - node_js: iojs 9 | - node_js: '0.12' 10 | - node_js: '6' 11 | -------------------------------------------------------------------------------- /app/stylesheets/main.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: #f0f0f0; 3 | color: #333; 4 | font-family: Helvetica; 5 | } 6 | 7 | input[type="text"] { 8 | margin-right: 1rem; 9 | } 10 | 11 | form { 12 | margin-bottom: 1rem; 13 | } -------------------------------------------------------------------------------- /app/src/components/product-row.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default ({product}) => { 4 | var name = product.stocked ? product.name : {product.name} ; 5 | return ( 6 | 7 | {name} 8 | {product.price} 9 | 10 | ); 11 | }; -------------------------------------------------------------------------------- /app/main.jsx: -------------------------------------------------------------------------------- 1 | import './stylesheets/main.css'; 2 | import React from 'react'; 3 | import {render} from 'react-dom'; 4 | import FilterableProductTable from './src/filterable-product-table'; 5 | 6 | // init shell 7 | initShell(); 8 | 9 | function initShell() { 10 | var shell = document.createElement('main'); 11 | shell.className = 'app-shell'; 12 | document.body.appendChild(shell); 13 | render(, shell); 14 | } -------------------------------------------------------------------------------- /app/src/models/products.jsx: -------------------------------------------------------------------------------- 1 | export default [ 2 | {category: "Sporting Goods", price: "$49.99", stocked: true, name: "Football"}, 3 | {category: "Sporting Goods", price: "$9.99", stocked: true, name: "Baseball"}, 4 | {category: "Sporting Goods", price: "$29.99", stocked: false, name: "Basketball"}, 5 | {category: "Electronics", price: "$99.99", stocked: true, name: "iPod Touch"}, 6 | {category: "Electronics", price: "$399.99", stocked: false, name: "iPhone 5"}, 7 | {category: "Electronics", price: "$199.99", stocked: true, name: "Nexus 7"} 8 | ]; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React (15.6.0) example using ES2015 [![Build Status](https://travis-ci.org/code0wl/react-example-modern-javascript.svg?branch=master)](https://travis-ci.org/code0wl/react-example-modern-javascript) 2 | 3 | On the react site there is a demo on how to learn to think with react. This is the same tutorial executed using ES2015 and webpack as a build process. There are some gotcha's transforming your code to ES2015 whilst using React. In this demo there is a solution for these common challenges. 4 | 5 | Follow the original and great tutorial here 6 | [Es5 thinking in React](https://facebook.github.io/react/docs/thinking-in-react.html) and check the syntax differences using this project. 7 | [Changelog found here](https://facebook.github.io/react/blog/2016/11/16/react-v15.4.0.html) 8 | 9 | ``` 10 | npm start 11 | ``` 12 | 13 | Check the app at http://localhost:8080 14 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var webpack = require('webpack'); 3 | var ROOT_PATH = path.resolve(__dirname); 4 | var HtmlWebpackPlugin = require('html-webpack-plugin'); 5 | 6 | module.exports = { 7 | 8 | entry: [path.resolve(ROOT_PATH, 'app/main.jsx')], 9 | 10 | resolve: { 11 | extensions: ['', '.js', '.jsx'] 12 | }, 13 | 14 | output: { 15 | path: path.resolve(ROOT_PATH, 'build'), 16 | filename: 'bundle.js' 17 | }, 18 | 19 | plugins: [ 20 | new HtmlWebpackPlugin({ 21 | title: 'React ES2015' 22 | }) 23 | ], 24 | 25 | module: { 26 | loaders: [ 27 | { 28 | test: /\.jsx?$/, 29 | exclude: /node_modules/, 30 | loader: "babel", 31 | query: { 32 | presets: ['es2015', 'react'] 33 | } 34 | }, 35 | 36 | { 37 | test: /\.css$/, 38 | loaders: ['style', 'css'] 39 | } 40 | ] 41 | } 42 | }; 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | build 3 | .DS_Store 4 | app/.DS_Store 5 | *.log 6 | .vscode 7 | 8 | ### JetBrains template 9 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion 10 | 11 | *.iml 12 | 13 | ## Directory-based project format: 14 | .idea/ 15 | # if you remove the above rule, at least ignore the following: 16 | 17 | # User-specific stuff: 18 | # .idea/workspace.xml 19 | # .idea/tasks.xml 20 | # .idea/dictionaries 21 | 22 | # Sensitive or high-churn files: 23 | # .idea/dataSources.ids 24 | # .idea/dataSources.xml 25 | # .idea/sqlDataSources.xml 26 | # .idea/dynamic.xml 27 | # .idea/uiDesigner.xml 28 | 29 | # Gradle: 30 | # .idea/gradle.xml 31 | # .idea/libraries 32 | 33 | # Mongo Explorer plugin: 34 | # .idea/mongoSettings.xml 35 | 36 | ## File-based project format: 37 | *.ipr 38 | *.iws 39 | 40 | ## Plugin-specific files: 41 | 42 | # IntelliJ 43 | /out/ 44 | 45 | # mpeltonen/sbt-idea plugin 46 | .idea_modules/ 47 | 48 | # JIRA plugin 49 | atlassian-ide-plugin.xml 50 | 51 | # Crashlytics plugin (for Android Studio and IntelliJ) 52 | com_crashlytics_export_strings.xml 53 | crashlytics.properties 54 | crashlytics-build.properties 55 | -------------------------------------------------------------------------------- /app/src/components/product-table.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import CategoryRow from './category-row'; 3 | import ProductRow from './product-row'; 4 | 5 | export default ({products, filterText, inStockOnly}) => { 6 | 7 | let rows = [], lastCategory = null; 8 | 9 | products.map((product) => { 10 | if (!product.name.toLowerCase().includes(filterText.toLowerCase()) || (!product.stocked && inStockOnly)) { 11 | return; 12 | } 13 | 14 | if (product.category !== lastCategory) { 15 | rows.push(); 16 | } 17 | 18 | rows.push(); 19 | lastCategory = product.category; 20 | 21 | }); 22 | 23 | if (rows.length > 0) { 24 | return ( 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | {rows} 33 |
NamePrice
34 | ); 35 | } else { 36 | return

\_(ツ)_/¯

; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/src/filterable-product-table.jsx: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import ProductTable from './components/product-table'; 3 | import SearchBar from './components/search-bar'; 4 | import products from './models/products'; 5 | 6 | class FilterableProductTable extends Component { 7 | 8 | constructor() { 9 | super(); 10 | 11 | this.handleUserInput = this.handleUserInput.bind(this); 12 | 13 | this.state = { 14 | filterText: '', 15 | inStockOnly: false 16 | } 17 | } 18 | 19 | handleUserInput(filterText, inStockOnly) { 20 | this.setState({ 21 | filterText: filterText, 22 | inStockOnly: inStockOnly 23 | }); 24 | } 25 | 26 | render() { 27 | return ( 28 |
29 | 33 | 37 |
38 | ) 39 | } 40 | 41 | } 42 | 43 | export default FilterableProductTable; 44 | -------------------------------------------------------------------------------- /app/src/components/search-bar.jsx: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | 3 | class SearchBar extends Component { 4 | 5 | constructor() { 6 | super(); 7 | this.handleChange = this.handleChange.bind(this); 8 | } 9 | 10 | handleChange() { 11 | this.props.onUserInput( 12 | this.refs['filterTextInput'].value, 13 | this.refs['inStockOnlyInput'].checked 14 | ); 15 | } 16 | 17 | render() { 18 | return ( 19 |
20 | 27 | 28 | 34 | {' '} 35 | Only show products in stock 36 | 37 |
38 | ); 39 | } 40 | } 41 | 42 | export default SearchBar; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "modern-javascript-react", 3 | "version": "1.0.0", 4 | "description": "React es15 in best practice style.", 5 | "main": "webpack.config.js", 6 | "devDependencies": { 7 | "babel": "~6.5.2", 8 | "babel-cli": "~6.10.1", 9 | "babel-core": "~6.9.1", 10 | "babel-loader": "~6.2.4", 11 | "babel-preset-es2015": "~6.9.0", 12 | "babel-preset-react": "^6.5.0", 13 | "css-loader": "^0.23.1", 14 | "cssesc": "^0.1.0", 15 | "flatten": "1.0.2", 16 | "html-webpack-plugin": "^2.21.0", 17 | "http-server": "^0.9.0", 18 | "indexes-of": "^1.0.1", 19 | "node-libs-browser": "^1.0.0", 20 | "normalize": "^0.3.1", 21 | "style-loader": "^0.13.1", 22 | "webpack": "~1.13.1", 23 | "webpack-dev-server": "~1.14.1", 24 | "webpack-merge": "~0.14.0" 25 | }, 26 | "private": false, 27 | "scripts": { 28 | "build": "webpack", 29 | "start": "npm i && webpack && node ./node_modules/http-server/bin/http-server ./build -p 8080 -o" 30 | }, 31 | "repository": { 32 | "type": "git", 33 | "url": "git+https://github.com/Ositoozy/react-example-es2015.git" 34 | }, 35 | "author": "Oscar Lodriguez", 36 | "license": "ISC", 37 | "bugs": { 38 | "url": "https://github.com/Ositoozy/react-example-es2015.git/issues" 39 | }, 40 | "homepage": "https://github.com/Ositoozy/react-example-es2015.git#readme", 41 | "dependencies": { 42 | "react": "15.6.0", 43 | "react-dom": "15.6.0", 44 | "tapable": "^0.2.4" 45 | } 46 | } 47 | --------------------------------------------------------------------------------