React.js con material-ui

Rutas y arquitectura de la aplicación

  • Utilizaremos un starter kit:
  • Hacemos un clone del proyecto e instalamos dependencias:
npm install
  • Instalamos react router:

    npm i -S react-router
    
  • El código que a continuación utilizaremos está formateado sin acabar en ";". Por ello:

    • Configuraremos eslint de esta forma. Añadimos la regla en el fichero .eslintrc:

      "semi": [2, "never"]
      
    • Corregiremos el código presente:

      node_modules/.bin/eslint --fix .
      
  • Ahora modificaremos nuestros ficheros fuente. En nuestro componente <App/> nos encargaremos de renderizar nuestro enrutador (no deja de ser otro componente) que será el que se encargue de cargar las distintas vistas:

    import React, { Component } from 'react'
    import { Router, Route, browserHistory } from 'react-router'
    import Index from './views/Index'
    import Contactar from './views/Contactar'
    import Cervezas from './views/Cervezas'
    
    export default class App extends Component {
      render() {
        return (
          <Router history={browserHistory}>
            <Route path="/" component={Index}/>
            <Route path="/cervezas" component={Cervezas}/>
            <Route path="/contactar" component={Contactar}/>
          </Router>
        )
      }
    }
    
  • Las vistas serán de momento algo tal como:

    import React, {Component} from 'react'
    
    export default class Cervezas extends Component {
      render() {
        return (
          <h1>Mi lista de cervezas</h1>
        )
      }
    }
    
  • Vamos a intentar hacer ahora rutas anidadas. En la ruta base, cargaremos una plantilla que será la encargada de colocar el menú, header y footer para todas las páginas:

    import React, { Component } from 'react'
    import { Router, Route, browserHistory, IndexRoute } from 'react-router'
    import Index from './views/Index'
    import Contactar from './views/Contactar'
    import Cervezas from './views/Cervezas'
    import Template from './layout/Template'
    
    export default class App extends Component {
      render() {
        return (
          <Router history={browserHistory}>
            <Route path='/' component={Template}>
              /*observa que definimos IndexRoute, que será la ruta por defecto*/
              /*Todas las rutas siguientes están anidadas dentro de template, es decir
              son hijas de la anterior y desde la template cargaremos la que corresponda*/
              <IndexRoute component={Index}/>
              <Route path='cervezas' component={Cervezas}/>
              <Route path='/contactar' component={Contactar}/>
            </Route>
          </Router>
        )
      }
    }
    
  • Creo una carpeta llamada layout donde colocaremos el footer, header y resto de componentes asociados a la plantilla. De momento la plantilla con el siguiente código:
import React, {Component} from 'react'

export default class Template extends Component {
  render() {
    return (
      <div>
        <header><h1>Sitio web de mis cervezas</h1></header>
        <main>{this.props.children}</main>
        <footer>Realizado por juanda</footer>
      </div>
    )
  }
}

Integración con material-ui

  • Lo primero que debemos hacer es instalar y configurar material-ui para el uso en nuestra aplicación:

    npm i -S material-ui react-tap-event-plugin
    
  • En el fichero app.js:

    import injectTapEventPlugin from 'react-tap-event-plugin';
    
    // Needed for onTouchTap
    // Check this repo:
    // https://github.com/zilverline/react-tap-event-plugin
    injectTapEventPlugin();
    
  • En el index.html:

    <link href='https://fonts.googleapis.com/css?family=Roboto:400,300,500' rel='stylesheet' type='text/css'>
    
  • Comprobamos si funciona o no, mediante un npm start y vemos que los warnings que nos han salido en la instalación hay que arreglarlos: ciertos errores de dependencias que nos obligan a actualizar la versión de react y react-dom

Creo el componente Menu.js copiando código de la web de Material-ui:

  import React from 'react'
  import Drawer from 'material-ui/Drawer'
  import MenuItem from 'material-ui/MenuItem'
  import RaisedButton from 'material-ui/RaisedButton'

  export default class Menu extends React.Component {

    constructor(props) {
      super(props);
      this.state = {open: false};
    }

    handleToggle = () => this.setState({open: !this.state.open});

    render() {
      return (
        <div>
          <RaisedButton
            label="Toggle Drawer"
            onTouchTap={this.handleToggle}
          />
          <Drawer open={this.state.open}>
            <MenuItem>Menu Item</MenuItem>
            <MenuItem>Menu Item 2</MenuItem>
          </Drawer>
        </div>
      )
    }
  }
  • En la template lo tengo que llamar:

    import React, {Component} from 'react'
    import Menu from './Menu.js'
    
    export default class Template extends Component {
      render() {
        return (
          <div>
            <header><h1>Sitio web de mis cervezas</h1></header>
            <Menu/>
            <main>{this.props.children}</main>
            <footer>Realizado por juanda</footer>
          </div>
        )
      }
    }
    
  • Comprobamos que no funciona ya que para usar los componentes de Material-ui es necesario utilizar un theme. Lo añadimos tal y como marca la documentación, en el fichero App.js:

import React, { Component } from 'react'
import { Router, Route, browserHistory, IndexRoute } from 'react-router'
import Index from './views/Index'
import Contactar from './views/Contactar'
import Cervezas from './views/Cervezas'
import Template from './layout/Template'

import getMuiTheme from 'material-ui/styles/getMuiTheme'
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider'

import injectTapEventPlugin from 'react-tap-event-plugin'

  // Needed for onTouchTap
  // Check this repo:
  // https://github.com/zilverline/react-tap-event-plugin
injectTapEventPlugin()

export default class App extends Component {
  render() {
    return (
      <MuiThemeProvider muiTheme={getMuiTheme()}>
        <Router history={browserHistory}>
          <Route path='/' component={Template}>
            /*observa que definimos IndexRoute, que será la ruta por defecto*/
            /*Todas las rutas siguientes están anidadas dentro de template, es decir
            son hijas de la anterior y desde la template cargaremos la que corresponda*/
            <IndexRoute component={Index}/>
            <Route path='cervezas' component={Cervezas}/>
            <Route path='/contactar' component={Contactar}/>
          </Route>
        </Router>
      </MuiThemeProvider>    
    )
  }
}
  • Si lo ejecutamos ahora veremos que funciona. Sin embargo el botón queda escondido detrás del menú. Lo podemos arreglar utilizando css directamente desde el JavaScript:
import React from 'react'
import Drawer from 'material-ui/Drawer'
import MenuItem from 'material-ui/MenuItem'
import RaisedButton from 'material-ui/RaisedButton'

const styles = {
  container: {
    width:'800px',
    margin: '0 auto'
  }
}

export default class Menu extends React.Component {

  constructor(props) {
    super(props);
    this.state = {open: false};
  }

  handleToggle = () => this.setState({open: !this.state.open});

  render() {
    return (
      <div style={styles.container}>
        <RaisedButton
          label="Toggle Drawer"
          onTouchTap={this.handleToggle}
        />
        <Drawer open={this.state.open}>
          <MenuItem>Menu Item</MenuItem>
          <MenuItem>Menu Item 2</MenuItem>
        </Drawer>
      </div>
    )
  }
}

Más tareas

  • Podríamos añadir otros componentes pero la tarea no deja de ser similar.
  • Quizá podríamos utilizar un sistema de rejilla tipo Bootstrap para colocar los elementos y ahorrarnos código css o js. Una buena opción sería http://flexboxgrid.com/.

results matching ""

    No results matching ""