e

Agregar estilos a la aplicación React

La apariencia de nuestra aplicación actual es bastante modesta . En el ejercicio 0.2, la tarea era pasar por el tutorial CSS de Mozilla.

Antes de pasar a la siguiente parte, echemos un vistazo a cómo podemos agregar estilos a una aplicación React. Hay varias formas diferentes de hacer esto y veremos los otros métodos más adelante. Al principio, agregaremos CSS a nuestra aplicación a la vieja usanza; en un solo archivo sin usar un preprocesador CSS (aunque esto no es del todo cierto como veremos más adelante).

Agreguemos un nuevo archivo index.css en el directorio src y luego agréguelo a la aplicación importándolo en el archivo index.js:

import './index.css'

Agreguemos la siguiente regla CSS al archivo index.css:

h1 {
  color: green;
}

Las reglas CSS se componen de selectores y declaraciones. El selector define a qué elementos se debe aplicar la regla. El selector de arriba es h1, que coincidirá con todas las etiquetas de encabezado h1 en nuestra aplicación.

La declaración establece la propiedad color en el valor green.

Una regla CSS puede contener un número arbitrario de propiedades. Modifiquemos la regla anterior para convertir el texto en cursiva, definiendo el estilo de fuente como italic:

h1 {
  color: green;
  font-style: italic;}

Hay muchas formas de hacer coincidir elementos usando diferentes tipos de selectores CSS.

Si quisiéramos apuntar, digamos, a cada una de las notas con nuestros estilos, podríamos usar el selector li, ya que todas las notas están envueltas dentro de las etiquetas li:

const Note = ({ note, toggleImportance }) => {
  const label = note.important 
    ? 'make not important' 
    : 'make important';

  return (
    <li>
      {note.content} 
      <button onClick={toggleImportance}>{label}</button>
    </li>
  )
}

Agreguemos la siguiente regla a nuestra hoja de estilo (ya que mi conocimiento de diseño web elegante es cercano a cero, los estilos no tienen mucho sentido):

li {
  color: grey;
  padding-top: 3px;
  font-size: 15px;
}

El uso de tipos de elementos para definir reglas CSS es un poco problemático. Si nuestra aplicación contuviera otras etiquetas li, también se les aplicaría la misma regla de estilo.

Si queremos aplicar nuestro estilo específicamente a las notas, entonces es mejor usar selectores de clases.

En HTML normal, las clases se definen como el valor del atributo class:

<li class="note">some text...</li>

En React tenemos para usar el atributo className en lugar del atributo de clase. Con esto en mente, hagamos los siguientes cambios en nuestro componente Note:

const Note = ({ note, toggleImportance }) => {
  const label = note.important 
    ? 'make not important' 
    : 'make important';

  return (
    <li className='note'>      {note.content} 
      <button onClick={toggleImportance}>{label}</button>
    </li>
  )
}

Los selectores de clase se definen con la sitaxis .classname:

.note {
  color: grey;
  padding-top: 5px;
  font-size: 15px;
}

Si ahora agrega otros elementos li a la aplicación, no se verán afectados por la regla de estilo anterior.

Mensaje de error mejorado

Anteriormente implementamos el mensaje de error que se mostraba cuando el usuario intentaba cambiar la importancia de una nota eliminada con el método alert. Implementemos el mensaje de error como su propio componente React.

El componente es bastante simple:

const Notification = ({ message }) => {
  if (message === null) {
    return null
  }

  return (
    <div className="error">
      {message}
    </div>
  )
}

Si el valor del prop message es null, no se muestra nada en la pantalla y, en otros casos, el mensaje se representa dentro de un elemento div.

Agreguemos un nuevo estado llamado errorMessage al componente App. Inicialicemos con algún mensaje de error para que podamos probar inmediatamente nuestro componente:

const App = () => {
  const [notes, setNotes] = useState([]) 
  const [newNote, setNewNote] = useState('')
  const [showAll, setShowAll] = useState(true)
  const [errorMessage, setErrorMessage] = useState('some error happened...')
  // ...

  return (
    <div>
      <h1>Notes</h1>
      <Notification message={errorMessage} />      <div>
        <button onClick={() => setShowAll(!showAll)}>
          show {showAll ? 'important' : 'all' }
        </button>
      </div>      
      // ...
    </div>
  )
}

Entonces agreguemos una regla de estilo que se adapte a un mensaje de error:

.error {
  color: red;
  background: lightgrey;
  font-size: 20px;
  border-style: solid;
  border-radius: 5px;
  padding: 10px;
  margin-bottom: 10px;
}

Ahora estamos listos para agregar la lógica para mostrar el mensaje de error. Cambiemos la función toggleImportanceOf de la siguiente manera:

  const toggleImportanceOf = id => {
    const note = notes.find(n => n.id === id)
    const changedNote = { ...note, important: !note.important }

    noteService
      .update(changedNote).then(returnedNote => {
        setNotes(notes.map(note => note.id !== id ? note : returnedNote))
      })
      .catch(error => {
        setErrorMessage(          `Note '${note.content}' was already removed from server`        )        setTimeout(() => {          setErrorMessage(null)        }, 5000)        setNotes(notes.filter(n => n.id !== id))
      })
  }

Cuando ocurre el error, agregamos un mensaje de error descriptivo al estado errorMessage. Al mismo tiempo, iniciamos un temporizador que establecerá el estado de errorMessage en null después de cinco segundos.

El resultado se ve así:

fullstack content

El código para el estado actual de nuestra aplicación se puede encontrar en la rama part2-7 en github.

Estilos en línea

React también hace posible escribir estilos directamente en el código como los llamados estilos en línea.

La idea detrás de la definición de estilos en línea es extremadamente simple. Cualquier componente o elemento de React puede recibir un conjunto de propiedades CSS como un objeto JavaScript a través del atributo style.

Las reglas de CSS se definen de forma ligeramente diferente en JavaScript que en los archivos CSS normales. Digamos que queremos darle a algún elemento el color verde y la fuente en cursiva que tiene un tamaño de 16 píxeles. En CSS, se vería así:

{
  color: green;
  font-style: italic;
  font-size: 16px;
}

Pero como un objeto de estilo en línea de React se vería así:

 {
  color: 'green',
  fontStyle: 'italic',
  fontSize: 16
}

Cada propiedad CSS se define como una propiedad separada del objeto JavaScript. Los valores numéricos de los píxeles se pueden definir simplemente como números enteros. Una de las principales diferencias en comparación con el CSS normal es que las propiedades CSS con guiones (kebab case) están escritas en camelCase.

A continuación, podríamos agregar un "bloque inferior" a nuestra aplicación creando un componente Footer y definir los siguientes estilos en línea para él:

const Footer = () => {  const footerStyle = {    color: 'green',    fontStyle: 'italic',    fontSize: 16  }  return (    <div style={footerStyle}>      <br />      <em>Note app, Department of Computer Science, University of Helsinki 2020</em>    </div>  )}
const App = () => {
  // ...

  return (
    <div>
      <h1>Notes</h1>

      <Notification message={errorMessage} />

      // ...  

      <Footer />    </div>
  )
}

Los estilos en línea tienen ciertas limitaciones. Por ejemplo, las llamadas pseudoclases no se pueden usar directamente.

Los estilos en línea y algunas de las otras formas de agregar estilos a los componentes de React van completamente en contra de las viejas convenciones. Tradicionalmente, se ha considerado la mejor práctica para separar completamente CSS del contenido (HTML) y la funcionalidad (JavaScript). Según esta vieja escuela de pensamiento, el objetivo era escribir CSS, HTML y JavaScript en sus archivos separados.

La filosofía de React es, de hecho, el polo opuesto a esto. Dado que la separación de CSS, HTML y JavaScript en archivos separados no pareció escalar bien en aplicaciones más grandes, React basa la división de la aplicación en las líneas de sus entidades funcionales lógicas.

Las unidades estructurales que componen las entidades funcionales de la aplicación son componentes de React. Un componente de React define el HTML para estructurar el contenido, las funciones de JavaScript para determinar la funcionalidad y también el estilo del componente; todo en un lugar. Esto es para crear componentes individuales que sean lo más independientes y reutilizables como sea posible.

El código de la versión final de nuestra aplicación se puede encontrar en la rama part2-8 en github.