Taller: React con hooks II

Segunda entrada del taller con hooks para pasar la cuarentena.

Catrin Welz-Stein

archivado en: JavaScript / 24 marzo, 2020

Seguimos con este taller de react con hooks y typescript para sobrellevar el confinamiento y de paso, espero, aprender algo chulo. En la entrada anterior dejamos preparada toda la estructura, vamos ahora darle algo de alegría : )

Un componente con estilo

Vamos con nuestro primer componente transversal, la cabecera, que nos servirá para empezar a trabajar los estilos. Recuerda que este tipo de componentes lo situamos en src/components, donde podemos incluirlo entre los compos relacionados con el layout. Como no recibe ningún tipo de propiedad, no se diferencia apenas de los componentes sencillos del react clásico.

// src/components/layout/main-header.tsx

import React from 'react';

export const MainHeader: React.FC = ()  => {
  return (
    <header className="main-header" role="banner" data-qa="mainHeader">
      <h1 className="main-header__title">Dogs!</h1>
      <small className="main-header__aside">a canine application</small>
    </header>
  );
};

El atributo data-qa="mainHeader" nos servirá más adelante, cuando comencemos con los tests e2e. Además, lleva unas clases que siguen la metodología BEM (bloque - elemento - modificador). Vamos a prepararlas siguiendo, recuerda, el patrón 7 x 1 de SASS.

En el directorio assets/scss/base, preparamos un archivo para los colores, que pueden ser estos o los que sean.

/* src/assets/scss/base/_colors.scss */

$base-theme-lighten-01: #eceff1;
$base-theme-lighten-02: #cfd8dc;
$base-theme-lighten-03: #b0bec5;
$base-theme: #607d8b;
$base-theme-darken-01: #546e7a;
$base-theme-darken-02: #37474f;
$base-theme-darken-03: #263238;

$danger: #c62828;
$warning: #ff9100;
$info: #0277bd;
$success: #76ff03;

Añadimos unas fuentes, que de nuevo pueden ser las que se quieran.

/* src/assets/scss/base/_fonts.scss */

@font-face {
  font-family: 'dogs-theme';
  src: url('../../fonts/Spartan-Medium.ttf') format('truetype');
}

@font-face {
  font-family: 'dogs-theme-semi-bold';
  src: url('../../fonts/Spartan-SemiBold.ttf') format('truetype');
  font-weight: bold;
}

Incorporamos una sombras rollito materialize también el directorio base.

/* src/assets/scss/base/_shadows.scss */

@mixin depth-02 {
  box-shadow:
    0 2px 2px 0 rgba(0,0,0,0.14),
    0 3px 1px -2px rgba(0,0,0,0.12),
    0 1px 5px 0 rgba(0,0,0,0.2);
}

@mixin depth-03 {
  box-shadow:
    0 4px 5px 0 rgba(0,0,0,0.14),
    0 1px 10px 0 rgba(0,0,0,0.12),
    0 2px 4px -1px rgba(0,0,0,0.3);
}

@mixin depth-04 {
  box-shadow:
    0 8px 17px 2px rgba(0,0,0,0.14),
    0 3px 14px 2px rgba(0,0,0,0.12),
    0 5px 5px -3px rgba(0,0,0,0.2);
}

Añadimos, también en /base, algo para normalizar los estilos, que no voy a copiar por lo extenso, como las normalize.css.

Y ya en el directorio layout preparamos los estilos de la cabecera principal.

/* src/assets/scss/layout/_header.scss */

.main-header {
  padding: 1rem;
  background: $base-theme-darken-03;
  text-align: center;
  font-weight: bold;
  border-bottom: 20px solid $base-theme-darken-01;
  box-sizing: border-box;

  &__title {
    font-size: 2.5rem;
    line-height: 160%;
    color: $base-theme-lighten-01;
  }

  &__aside {
    font-size: 1.5rem;
    color: $base-theme-lighten-02;
  }
}

Lo importamos todo en index.scss.

/* src/assets/scss/index.scss */

@import 'base/reset';
@import 'base/colors';
@import 'base/fonts';
@import 'base/shadows';

@import 'layout/header';

Y ya solo nos falta añadir los estilos y el componente en App.tsx.

// src/App.tsx

import React from 'react';

import { BrowserRouter as Router } from 'react-router-dom';
import { Routes } from './routes/routes';

import './assets/scss/index.scss';
import { MainHeader } from './components/layout/main-header';

const App: React.FC = () => {
  return (
    <div>
       <MainHeader/>
      <Router>
        <Routes></Routes>
      </Router>
    </div>
  );
}

export default App;

Nuestra aplicación ahora debería verse más o menos así.

Nota: Hay otras maneras de trabajar los estilos en React, como los styledComponents, pero por experiencia, sobre todo a la que se trata de un proyecto grande, creo que es mucho más saludable y efectivo el sistema clásico de trabajar con Sass.

Not found

Vamos ahora con la vista más sencilla que tenemos entre manos, el equivalente a la página 404, pero antes vamos a preparar otro componente transversal, que podemos llamar Message, que nos va a servir para mostrar mensajes, que en este caso será de error.

Este componente ya sí que recibe unas propiedades -el mensaje a mostrar y el tipo de mensaje que es (error, warning, success....). Y como estamos usando typeScript, en lugar de PropTypes, vamos a tiparlas en un interfaz, que no hace falta sacar fuera del componente. Algo así:

// src/components/ui/message.tsx

import React from 'react';

interface IntMessage {
  type: string;
  message?: string;
}

const Message: React.FC<IntMessage> = (props)  => {
  return (
    <div className={`message message--${props.type}`} data-qa="messages" role="complementary">
      { props.message && props.message !== '' ? props.message : 'Something sinister has happened' }
    </div>
  );
};

export default Message;

Nota: A mí me gusta comenzar el nombre de los interfaces con la partícula Int, que así luego me queda más claro, pero tú mismo...

Le damos un par de estilos.

/* src/assets/scss/components/message.scss */

.message {
  padding: 1rem;
  font-size: 1rem;
  font-weight: bold;
  @include depth-04;

  &--error {
    color: $danger;
    border: 1px solid $danger;
  }

  &--warning {
    color: $warning;
    border: 1px solid $warning;
  }

  &--info {
    color: $info;
    border: 1px solid $info;
  }

  &--success {
    color: $success;
    border: 1px solid $success;
  }
}

Incluimos esos estilos en las importaciones del index.scss.

/* src/assets/scss/index.scss */

@import 'base/reset';
@import 'base/colors';
@import 'base/fonts';

@import 'layout/header';

@import 'components/message';

Y ahora podemos refactorizar la vista not-found.tsx para incluir el nuevo componente Message.

// src/views/not-found/view-not-found.tsx

import React from 'react';
import Message from '../../components/ui/message';

const ViewNotFound: React.FC = () => {
  return (
    <section className="page">
      <Message type="warning" message="Page not found" />
    </section>
  );
}

export default ViewNotFound;

Además, vamos a añadirle una clase "page", común a todas las vistas, que añadimos a las scss.

/* src/assets/scss/layout/_pages.scss */

.page {
  margin: 2rem;
}

Y, claro está, añadimos este parcial en el index.scss.

/* src/assets/scss/index.scss */
...
@import 'layout/header';
@import 'layout/pages';
...

Bueno, pues si ahora ponemos en la url cualquier dirección, como no la tenemos indicada en el router que definimos en la entrada anterior, debería cargarse la página de not-found con el componente Message. Algo así:

Vale, pues de momento vamos a dejarlo aquí.

Mucho ánimo a tod@s en estos días, que de esta vamos a salir más pronto que tarde.

|| Tags: , , ,

valoración de los lectores sobre Taller: React con hooks II

  • estrellica valoración positiva
  • estrellica valoración positiva
  • estrellica valoración positiva
  • estrellica valoración positiva
  • estrellica valoración positiva
  • 5 sobre 5 (1 votos)

¿Te ha parecido útil o interesante esta entrada?
dormido, valoración 1 nadapensativo, valoración 2 un poco sonrisa, valoración 3 a medias guiño, valoración 4 bastante aplauso, valoración 5 mucho

Tú opinión es muy importante, gracias por compartirla!

Los comentarios están cerrados.