ReactJS + LoopbackJS + MySQL [Parte 2]
Habiendo realizado la parte 1 vamos a proseguir con la parte 2. En esta parte, menos densa que la anterior, usaremos create-react-app para crear la aplicación con ReactJS. Y la pondremos a punto para el uso de las funciones CRUD:
- Create
- Read
- Update
- Delete
Para la parte visual usaré jQuery+Bootstrap principalmente. Pero podéis utilizar Materialize, o cualquier otro framework que queráis.
Para empezar debemos tener instalado desde los repositorios de npm/yarn create-react-app:
npm i -g create-react-app
Una vez instalado el paquete creamos una subcarpeta en dxcc-tutorial a la que llamaremos , dentro de la carpeta que acabamos de crear ejecutamos:
create-react-app .
Se descargarán e instalarán los paquetes react, react-dom y react-scripts, ademas de sus dependencias. Una vez instalado podemos ejecutar en el terminal.
npm start
o
yarn start
Si tenemos ejecutando el servidor de loopback, y no hemos cambiado el puerto por defecto, os alertará que ya está ocupado el puerto 3000 y si queremos ejecutarlo en el siguiente puerto libre 3001, confirmamos que sí. Si no está ejecutandose el servidor de loopback, se usará el puerto 3000.
En cualquier caso accederemos a http://localhost:{puerto} y debemos ver algo así:
Comprobamos que no hay ningún error y volvemos a apagar el servidor (ctrl+c). Y vamos a instalar algunos paquetes necesarios para este proyecto:
Lo haremos con:
npm install react-quill react-router react-router-dom axios --save
o
yarn add react-quill react-router react-router-dom axios
A partir de ahora ya podemos empezar a crear la aplicación
En nuestro editor vamos a la carpeta y abrimos el archivo public/index.html y en el head añadimos
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/css/toastr.css" /> <link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN" crossorigin="anonymous">
Cabiamos el title por el que queramos en el caso de este tutorial
<title>DXCC Tutorial</title>
Y justo antes del cerrar el body
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.3/umd/popper.min.js" integrity="sha384-vFJXuSJphROIrBnz7yo7oB41mKfc8JzQZiCq4NCceLEaO4IHwicKwpJf9c9IpFgh" crossorigin="anonymous"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/js/bootstrap.min.js" integrity="sha384-alpBpkh1PFOepccYVYDB4do5UnbKysX5WZXm3XxPqe5iKTfUKjNkCk9SaVuEZflJ" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/js/toastr.min.js"></script>
Nota: El paso anterior se puede saltar, a partir de este momento el código cambiará dependiendo del framework que se utilice.
Antes de continuar iniciamos el servidor (npm/yarn start) y vamos a poner un poco de orden en la ruta client_src/src.
Al finalizar esta parte la estructura deberá ser similar a lo siguiente:
- src
- components
- App
- App.css
- App.js
- Main.js
- Navbar.js
- Routes.js
- Apuntes
- Materias
- subcomps
- MateriasCard.js
- subcomps
- App
- index.css
- index.js
- registerServiceWorker.js
- components
Esta es la estructura que vamos a ir creado. Asi que empecemos creando las carpetas components y dentro App, y movemos App.css y App.js a la última carpeta que hemos creado.
Nota: Al ser React veréis que van apareciendo errores si tenéis abierta la página. Pero no os preocupéis porque los iremos solucionando.
Eliminamos el archivo App.test.js porque no lo vamos a usar. Abrimos el archivo index.js y modificamos la linea en la que importamos App
import App from './App';
y ponemos la nueva ruta donde encontrar App
import App from './components/App/App';
Añadimos también la linea
import { BrowserRouter } from 'react-router-dom';
Y por último cambiamos
ReactDOM.render(<App />, document.getElementById('root'));
por
ReactDOM.render( <BrowserRouter> <App /> </BrowserRouter> , document.getElementById('root'));
Para más información podéis ver la API
Abrimos el archivo App.js y lo editamos:
import React from 'react'; import './App.css'; import Main from './Routes'; import Navbar from './Navbar'; const App = () => ( <div> <Navbar /> <div className="container"> <Main /> </div> </div> ) export default App;
Como los archivo Routes.js y Navbar.js no existen, los creamos y los editamos.
import React from 'react'; import { Switch, Route } from 'react-router-dom'; import Main from './Main'; const Routes = () => ( <main> <Switch> <Route exact path='/' component={Main} /> </Switch> </main> ) export default Routes;
import React, { Component } from 'react'; import { Link } from 'react-router-dom'; export default class Navbar extends Component{ render(){ return( <nav className="navbar navbar-expand-lg sticky-top navbar-dark bg-info"> <Link className="navbar-brand" to="/">DXCC Tutorial</Link> <button className="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"> <span className="navbar-toggler-icon"></span> </button> <div className="collapse navbar-collapse" id="navbarSupportedContent"> <ul className="navbar-nav ml-md-auto"> <li className="nav-item active"> <Link className="nav-link" to="/"> <i className="fa fa-home" /> Inicio<span className="sr-only">(current)</span> </Link> </li> </ul> </div> </nav> ) } }
Tambien creamos el archivo Main.js
import React, { Component } from 'react'; import axios from 'axios'; import { Link } from 'react-router-dom'; export default class Main extends Component{ constructor(){ super(); this.state = { materias: [] } } componentWillMount(){ this.getMaterias(); } getCursos(){ axios.get('http://localhost:3000/api/Materias?filter[order]=created_at asc') .then(response => { this.setState({materias: response.data}, () => { //console.log(this.state); }) }) .catch(err => console.log(err)); } render(){ const materiasItems = this.state.materias.map((materia, i) => { return( <MateriasCards key={materia.id} materia={materia} /> ) }) return( <div className="row"> <div className="jumbotron justify-content-between row col-12 top-spacing-20"> <h1 className="col-4">DXCC Tutorial</h1> <Link to={'/cursoadd/'} className="btn btn-link btn-lg col-4"><i className="fa fa-plus" /></Link> </div> <div className="card-deck"> {materiasItems} </div> </div> ) } }
Y para cada uno de los cursos MateriasCard.js (en la carpeta Materias/subcomps)
import React, { Component } from 'react'; import { Link } from 'react-router-dom'; export default class MateriasCard extends Component{ constructor(props){ super(props); this.state = { materia : props.materia } } render(){ var desc; if( this.state.materia.descripcion == null || this.state.materia.descripcion.length < 180){ desc = this.state.materia.descripcion; }else{ desc = this.state.materia.descripcion.slice(0,180)+'[...]'; } return( <div className="card row"> <div className="card-header"> { this.state.materia.nombre } </div> <div className="card-body"> <p className="card-text" dangerouslySetInnerHTML={{ __html: this.state.materia.descripcion }}></p> </div> <div className="card-footer"> <Link to={`/materia/detail/${this.state.materia.id}`} className='btn btn-outline-success btn-block'>Detalles</Link> </div> </div> ) } }
Llegados a este punto ya deberíamos ver algo similar a:
Hasta aquí la segunda parte. Si todo funciona correctamente, hay que empezar con la tercera parte.
Si os habéis topado con algún fallo, o queréis aportar alguna idea o ayuda podéis dejar un comentario.
1 respuesta
[…] Si no ha habido ningún error, podéis avanzar a la siguiente parte. […]