├── .eslintrc ├── .gitignore ├── README.md ├── package.json ├── public ├── favicon.ico ├── index.html └── manifest.json ├── src ├── App.css ├── App.js ├── App.test.js ├── ContadorApp.js ├── data │ └── cars.json ├── index.css ├── index.js ├── logo.svg ├── registerServiceWorker.js └── sections │ ├── children.js │ ├── componentsWithComposition.js │ ├── componentsWithInheritance.js │ ├── conditional.js │ ├── events.js │ ├── fetch-example.js │ ├── forms.js │ ├── lists.js │ └── stateless-proptypes.js └── yarn.lock /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "react-app" 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Este repositorio está deprecado. Utiliza este que tiene archivos más actualizados. :) 2 | https://github.com/AprendiendoFrontend/Aprendiendo-React 3 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "udemy-curso", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "prop-types": "15.6.0", 7 | "react": "^15.6.1", 8 | "react-dom": "^15.6.1" 9 | }, 10 | "devDependencies": { 11 | "react-scripts": "1.0.7" 12 | }, 13 | "scripts": { 14 | "start": "react-scripts start", 15 | "build": "react-scripts build", 16 | "test": "react-scripts test --env=jsdom", 17 | "eject": "react-scripts eject" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/curso-udemy-react/7fe8e70b747b112676cb46a18a5d58ca08b95948/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | React App 23 | 24 | 25 | 28 |
29 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | animation: App-logo-spin infinite 20s linear; 7 | height: 80px; 8 | } 9 | 10 | .App-header { 11 | background-color: #222; 12 | height: 150px; 13 | padding: 20px; 14 | color: white; 15 | } 16 | 17 | .App-intro { 18 | font-size: large; 19 | } 20 | 21 | @keyframes App-logo-spin { 22 | from { transform: rotate(0deg); } 23 | to { transform: rotate(360deg); } 24 | } 25 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import FetchExample from './sections/fetch-example' 3 | 4 | class App extends Component { 5 | render () { 6 | return ( 7 |
8 | 9 |
10 | ); 11 | } 12 | } 13 | 14 | export default App; 15 | -------------------------------------------------------------------------------- /src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | }); 9 | -------------------------------------------------------------------------------- /src/ContadorApp.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | class Contador extends Component { 4 | constructor (props) { 5 | super(props) 6 | console.log(this.props.contadorInicial) 7 | this.state = { contador: this.props.contadorInicial } 8 | setInterval(() => { 9 | this.setState({ contador: this.state.contador + 1 }) 10 | }, 1000) 11 | } 12 | 13 | render () { 14 | return 15 | } 16 | } 17 | 18 | Contador.defaultProps = { 19 | contadorInicial: 0 20 | } 21 | 22 | class ContadorNumero extends Component { 23 | render () { 24 | console.log('ContadorNumero render()') 25 | return {this.props.numero} 26 | } 27 | } 28 | 29 | class App extends Component { 30 | render () { 31 | return ( 32 |
33 |

Propagando el state de nuestros componentes

34 | 35 |
36 | ); 37 | } 38 | } 39 | 40 | export default App; 41 | -------------------------------------------------------------------------------- /src/data/cars.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "efe1a0cd-8353-4ba0-d4v3-30434c933298", 4 | "name": "A3", 5 | "company": "Audi" 6 | }, 7 | { 8 | "id": "9b9048ec-fff8-4bc5-m1k3-d0c65b83eb92", 9 | "name": "Mondeo", 10 | "company": "Ford" 11 | }, 12 | { 13 | "id": "f447e8a1-26a2-4e3a-p3n3-724e93fd4945", 14 | "name": "Megane", 15 | "company": "Renault" 16 | }, 17 | { 18 | "id": "52f1c5b7-14b5-41c0-t3t4-42ef853a7648", 19 | "name": "A200", 20 | "company": "Mercedes" 21 | } 22 | ] 23 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0 16px; 4 | font-family: sans-serif; 5 | } 6 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | import registerServiceWorker from './registerServiceWorker'; 5 | import './index.css'; 6 | 7 | ReactDOM.render(, document.getElementById('root')); 8 | registerServiceWorker(); 9 | -------------------------------------------------------------------------------- /src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/registerServiceWorker.js: -------------------------------------------------------------------------------- 1 | // In production, we register a service worker to serve assets from local cache. 2 | 3 | // This lets the app load faster on subsequent visits in production, and gives 4 | // it offline capabilities. However, it also means that developers (and users) 5 | // will only see deployed updates on the "N+1" visit to a page, since previously 6 | // cached resources are updated in the background. 7 | 8 | // To learn more about the benefits of this model, read https://goo.gl/KwvDNy. 9 | // This link also includes instructions on opting out of this behavior. 10 | 11 | export default function register() { 12 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 13 | window.addEventListener('load', () => { 14 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 15 | navigator.serviceWorker 16 | .register(swUrl) 17 | .then(registration => { 18 | registration.onupdatefound = () => { 19 | const installingWorker = registration.installing; 20 | installingWorker.onstatechange = () => { 21 | if (installingWorker.state === 'installed') { 22 | if (navigator.serviceWorker.controller) { 23 | // At this point, the old content will have been purged and 24 | // the fresh content will have been added to the cache. 25 | // It's the perfect time to display a "New content is 26 | // available; please refresh." message in your web app. 27 | console.log('New content is available; please refresh.'); 28 | } else { 29 | // At this point, everything has been precached. 30 | // It's the perfect time to display a 31 | // "Content is cached for offline use." message. 32 | console.log('Content is cached for offline use.'); 33 | } 34 | } 35 | }; 36 | }; 37 | }) 38 | .catch(error => { 39 | console.error('Error during service worker registration:', error); 40 | }); 41 | }); 42 | } 43 | } 44 | 45 | export function unregister() { 46 | if ('serviceWorker' in navigator) { 47 | navigator.serviceWorker.ready.then(registration => { 48 | registration.unregister(); 49 | }); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/sections/children.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | class Box extends Component { 4 | render () { 5 | return ( 6 |
7 | {this.props.children} 8 |
9 | ) 10 | } 11 | } 12 | 13 | class Article extends Component { 14 | render () { 15 | return ( 16 |
17 |

{this.props.title}

18 |

Escrito por {this.props.author}

19 | {this.props.date} 20 |
21 | {this.props.children} 22 |
23 |
24 | ) 25 | } 26 | } 27 | 28 | class Children extends Component { 29 | render () { 30 | return ( 31 |
32 |

Children props

33 |
38 |

El contenido que envolvemos dentro del componente Article será enviado al componente como this.props.children.

39 | Y mantiene las etiquetas y componentes que hayáis añadido dentro 40 |
41 |
46 |

El contenido que envolvemos dentro del componente Article será enviado al componente como this.props.children.

47 | Y mantiene las etiquetas y componentes que hayáis añadido dentro 48 |
49 |
54 |

El contenido que envolvemos dentro del componente Article será enviado al componente como this.props.children.

55 | Y mantiene las etiquetas y componentes que hayáis añadido dentro 56 |
57 |
58 | ); 59 | } 60 | } 61 | 62 | export default Children; 63 | -------------------------------------------------------------------------------- /src/sections/componentsWithComposition.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | class Button extends Component { 4 | render () { 5 | return ( 6 | 9 | ) 10 | } 11 | } 12 | 13 | Button.defaultProps = { 14 | borderColor: '#09f' 15 | } 16 | 17 | class ButtonDanger extends Component { 18 | render () { 19 | return 14 | ) 15 | } 16 | } 17 | 18 | class ButtonDanger extends Button { 19 | constructor (props) { 20 | super(props) 21 | this.borderColor = 'red' 22 | } 23 | } 24 | 25 | class ButtonWithLegend extends Button { 26 | render () { 27 | return ( 28 |
29 | {super.render()} 30 | {this.props.legend} 31 |
32 | ) 33 | } 34 | } 35 | 36 | class ComponentsWithInheritance extends Component { 37 | render () { 38 | return ( 39 |
40 |

Composición vs. herencia (ejemplo de herencia)

41 |
49 | ); 50 | } 51 | } 52 | 53 | export default ComponentsWithInheritance; 54 | -------------------------------------------------------------------------------- /src/sections/conditional.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | 3 | class LoginButton extends Component { 4 | render () { 5 | return 6 | } 7 | } 8 | 9 | class LogoutButton extends Component { 10 | render () { 11 | return ( 12 |
13 |

Bienvenido, usuario!

14 | 15 |
16 | ) 17 | } 18 | } 19 | 20 | export default class ConditionalSection extends Component { 21 | constructor() { 22 | super() 23 | this.state = { isUserLogged: false } 24 | } 25 | 26 | render () { 27 | return ( 28 |
29 |

Conditional Rendering

30 | {this.state.isUserLogged 31 | ? 32 | : 33 | } 34 |
35 | ) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/sections/events.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | 3 | export default class Events extends Component { 4 | constructor () { 5 | super() 6 | this.state = { mouseX: 0, mouseY: 0 } 7 | // this.handleMouseMove = this.handleMouseMove.bind(this) 8 | } 9 | 10 | handleMouseMove = (e) => { 11 | const { clientX, clientY } = e 12 | this.setState({ mouseX: clientX, mouseY: clientY }) 13 | } 14 | 15 | handleClick (e) { 16 | console.log(e) 17 | console.log(e.nativeEvent) 18 | alert('Hi here!') 19 | } 20 | 21 | render () { 22 | return ( 23 |
24 |

Eventos

25 | 26 |
29 |

{this.state.mouseX}, {this.state.mouseY}

30 |
31 |
32 | ) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/sections/fetch-example.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | class FetchExample extends Component { 4 | state = { bpi: {}} 5 | 6 | componentDidMount () { 7 | fetch('https://api.coindesk.com/v1/bpi/currentprice.json') 8 | .then(res => res.json()) 9 | .then(data => { 10 | const { bpi } = data 11 | this.setState({ bpi }) 12 | }) 13 | } 14 | 15 | _renderCurrencies () { 16 | const { bpi } = this.state 17 | const currencies = Object.keys(bpi) // ['EUR', 'GBP', 'USD'] 18 | return currencies.map(currency => ( 19 |
20 | 1 BTC is {bpi[currency].rate} 21 | {currency} 22 |
23 | )) 24 | } 25 | 26 | render () { 27 | return ( 28 |
29 |

Bitcoin Price Index

30 | {this._renderCurrencies()} 31 |
32 | ) 33 | } 34 | } 35 | 36 | export default FetchExample 37 | -------------------------------------------------------------------------------- /src/sections/forms.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | 3 | export default class Forms extends Component { 4 | constructor () { 5 | super() 6 | this.state = { 7 | inputName: '', 8 | inputTwitter: '@', 9 | inputTerms: true 10 | } 11 | } 12 | 13 | handleSubmit = (e) => { 14 | e.preventDefault() 15 | console.log(this.state) 16 | } 17 | 18 | handleChange = (e) => { 19 | console.log('handleChange') 20 | console.log(e.target.checked) 21 | this.setState({ inputTerms: e.target.checked }) 22 | } 23 | 24 | render () { 25 | return ( 26 |
27 |

Formularios

28 |
29 |

30 | 31 | this.setState({ inputName: e.target.value })} 35 | placeholder='Introduce el nombre' 36 | ref={inputElement => this.inputName = inputElement} 37 | value={this.state.inputName} /> 38 |

39 | 40 |

41 | 42 | this.setState({ inputTwitter: e.target.value })} 46 | placeholder='Introduce tu Twitter' 47 | value={this.state.inputTwitter} /> 48 |

49 | 50 |

51 | 58 |

59 | 60 | 61 |
62 |
63 | ) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/sections/lists.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import cars from '../data/cars.json' 3 | 4 | class CarItem extends Component { 5 | render () { 6 | const { car, id } = this.props 7 | 8 | return ( 9 |
  • 10 |

    Key: {id}

    11 |

    Nombre: {car.name}

    12 |

    Marca: {car.company}

    13 |
  • 14 | ) 15 | } 16 | } 17 | 18 | export default class CarsList extends Component { 19 | render () { 20 | return ( 21 |
      22 | { 23 | cars.map(car => { 24 | return 25 | }) 26 | } 27 |
    28 | ) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/sections/stateless-proptypes.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types' 3 | 4 | function Article (props) { 5 | return ( 6 |
    7 |

    {props.title}

    8 |

    Escrito por {props.author}

    9 | {props.date} 10 |
    11 | {props.children} 12 |
    13 |
    14 | ) 15 | } 16 | 17 | Article.propTypes = { 18 | title: PropTypes.string.isRequired, 19 | author: PropTypes.string.isRequired, 20 | date: PropTypes.string.isRequired, 21 | children: PropTypes.any 22 | } 23 | 24 | const Button = ({ borderColor = 'red', label }) => ( 25 | 28 | ) 29 | 30 | Button.propTypes = { 31 | borderColor: PropTypes.string, 32 | label: PropTypes.string.isRequired 33 | } 34 | 35 | class StatelessWithPropTypes extends Component { 36 | render () { 37 | return ( 38 |
    39 |

    Stateless components

    40 |
    45 |

    El contenido que envolvemos dentro del componente Article será enviado al componente como this.props.children.

    46 | Y mantiene las etiquetas y componentes que hayáis añadido dentro 47 |
    48 |
    49 |
    51 | ) 52 | } 53 | } 54 | 55 | export default StatelessWithPropTypes 56 | --------------------------------------------------------------------------------