hand Inicio

SERVICIOS

Salir

nochedía

Diseña un grid masonry con react-spring

1300 palabras
5 minutos
July 23, 2020

React-spring es una librería fantástica basada en un física de movimiento de muelles o de oscilador armónico

Aquí vamos a utilizarla para recrear su ejemplo de la técnica masonry para posicionar elementos en una malla

Prólogo

La técnica masonry la vimos en su adaptación con css-grid y JavaScript en este curso

Aquí vamos a implementarla con la librería externa react-spring y siguiendo su ejemplo en codesandbox

Vamos allá

  1. Prólogo
  2. Entendiendo el código
  3. Ejemplos
  4. Técnica masonry
  5. Comentario

Entendiendo el código

React-spring nos ofrece una dinámica de movimiento realista basada en muelles, donde en lugar de ajustar tiempo y distancias ajustamos masa, tensión y fricción

A partir de aquí, la librería nos ofrece distintas herramientas (yo prefiero las versiones en hook) para implementar transiciones

Para el masonry, la que utilizamos es la useTransition

El hook consta de dos partes

La primera es el hook en sí

El hook nos devuelve un array de transiciones, y le tenemos que dar una serie de argumentos

  • ítems: una lista de elementos o de condiciones
  • una función para devolver keys asociadas a los elementos, o si se trata de una condición el valor será null
  • un objeto para definir lo que pasa al inicio from que es opcional, lo que pasa cuando se entra enter y cuando se deja leave la transición

La lista que devuelve la utilizamos para desplegar la animación, lo hacemos utilizando el componente <animated> que también importaremos

Ya ya estará, todo lo que tenga que ver con la animación en sí está encapsulado en los componentes <animated>

Vamos a ver algunos ejemplos

Ejemplos

Ejemplos para implementar distintos efectos, donde la utilización de react-spring lo que nos permite es conseguir esa física "amortiguada" que podemos modificar

Para cambiar la física modifica el objeto config

No te olvides de añadir las dependencias de react-spring y de styled-components en los codesandbox

Condición on/off

Aquí básicamente definimos dos estados en función de si el ítem que nos pasa la lista de transiciones (un único ítem) existe o no

Lista de elementos que se añaden

Vamos añadiendo o quitando elementos a la lista manualmente

Lista de elementos que se añaden con un sólo click

En este caso es lo mismo que el anterior, pero en lugar de añadir cada elemento manualmente, definimos una multi-transición para recrear una especie de dca.animación

Y la manera de hacerlo es con una secuencia orquestada por el await y el async

Fíjate que lo único que cambio son las transiciones

Lista de imágenes de las que necesitamos leer las dimensiones

Si queremos mostrar imágenes, necesitamos poder sacar las dimensiones sin necesidad de entrarlas manualmente

Esto nos irá muy bien para luego implementar lo mismo pero con la técnica masonry

Lo haremos con el custom hook useMeasure que nos devuelve la referencia y las dimensiones

En lugar de devolvernos una ref y que nosotros tengamos que poner

ya nos devuelve un objeto {ref: ref}

Con lo cual podemos simplemente volcar lo que nos recibe con

y así si en algún momento quisiéramos añadir alguna otra propiedad podríamos aprovechar esta estructura

Entonces, al poner la referencia en el elemento que queramos, automáticamente podremos acceder a sus dimensiones a través de la propiedad contentRect

Y esto lo hacemos evidentemente con un useState que se actualizará en cuanto asignemos esa referencia

Para emular las imágenes lo que haremos es generar unas dimensiones random y después leerlas como si fueran imágenes reales

Y esto lo haremos a través de una distribución en columna, esto es en una sola columna

En este caso el código se complica un poco

Primero tenemos el custom hook useMeasure, que nos devuelve la referencia y el contentRect, y a nivel interno inicializa un ResizeObserver que lo guarda en un estado y que cuando el componente se desmonta lo desconecta

Segundo tenemos la formación de imágenes que simplemente genera una lista con un height y un background aleatorios

Después el componente Image que utiliza el hook para volcar la referencia en la imagen y definirle las dimensiones (en realidad esas dimensiones vendrían dadas por la imagen, pero aquí se las damos porque las hemos creado artificialmente - y las he llamado unknownHeight)

Este componente llama a la función reSetElements que actualiza esas dimensiones (aquí sólo el height) en el estado pertinente

Y finalmente el componente principal Main donde genero la lista con un useState y utilizo las imágenes que he generado antes de inicio

También fijo la altura de la columna en cero

Para generar el efecto de posicionar los elementos react-spring necesita saber las coordenadas (lo hace posicionando los elementos con translate3d), que aquí como es sólo una columna se reduce a saber la posición y

Eso lo sabremos porque iremos colocando cada elemento uno a uno

Y en cuanto lo pongamos, iremos incrementando el valor de columnHeight, y así sabremos el siguiente elemento dónde posicionarlo (esto lo hacemos en el primer argumento de useTransition)

Luego generamos las transiciones con useTransition

El primer argumento es la lista de elementos, que es donde definimos para cada elemento su posición y

*En realidad el columnHeight nos sirve para contar las alturas, después no necesitamos ponerlo como estilo en <Div style={{ columnHeight }}>, pero lo ponemos porque para el masonry luego sí que lo necesitaremos especificar

El segundo argumento lo utilizamos para volcar la key

El tercer argumento lo utilizamos para definir las transiciones en sí

Y luego ya volcamos el JSX que utiliza el componente anterior <Image>

Hay una novedad y es el uso del estilo

Esta función interpolate nos la da react-spring e implementa la transición en sí

Técnica masonry

Y ahora ya sí, ya tenemos las bases para implementar una distribución masonry con react-spring

La diferencia con la anterior colocación de elementos en una columna es precisamente que aquí tendremos más columnas

Por lo tanto algo que haremos será calcular el número de columnas que podemos poner, y el ancho de las imágenes vendrá dado por este ancho de columna en lugar de fijarlo en 200px

Esto lo haremos responsive aprovechando el hook que nos dan en la documentación de react-spring en el mismo ejemplo masonry

A partir de aquí, utilizaremos la misma estrategia pero no sólo calcularemos la y de cada elemento sino también la x

Y también hay una parte de código para emular las imágenes que no sería demasiado relevante, ya que al volcar una imagen en html esta ocupa sus dimensiones intrínsecas

Cuando aquí lo hago con un <div> tengo que darle dimensiones específicas, y después quitárselas ya que sino no se adaptan

Excepto estos detalles, los códigos son muy parecidos

  • El useMedia nos devuelve el número de columnas dadas las dimensiones actuales de la ventana del navegador, y actualizándose a cada evento de resize

  • El useMeasure repite, lo utilizamos para todas las pseudo-imágenes y también para el contenedor donde va nuestra malla

  • Repetimos estructura de generación de imágenes, pero añadimos el currentRatio

Esto lo necesitamos porque escalaremos las imágenes

Si éstas están a 200x300 de original, pero la columna tiene un ancho de 150px, entonces utilizaré el ratio para calcular la height adaptada

  • El componente <Image> repite, aunque ahora monitoreo altura y anchura, y reseteo la estructura de los elementos sólo cuando hay una altura real

  • Luego ya tenemos el componente principal <Main> donde utilizo los hooks de antes y el estado donde guardaré la estructura de mis datos

  • La función para resetear esta estructura reSetElements fíjate que sólo actualiza el estado cuando no hay ninguna imagen con altura monitoreada de cero, es decir que se espera a que tengamos todas las alturas modificadas

Esto es un ejercicio de optimización, pero si tus imágenes son de servidores externos esto no lo querrás ya que si alguna imagen no se carga no te permitirá renderizar nada

  • La generación de las transiciones con useTransition

Parece complicada, pero al final se trata de

  • Calcular qué columna tiene la altura más baja para añadir allí en nuevo elemento
  • Calcular el ancho de esa columna, que será el ancho del elemento
  • Calcular la altura del elemento basado en ese ancho
  • Calcular las coordenadas X e Y donde irá ese elemento
  • Devolver el mismo elemento pero extendido con las coordenadas, anchura y altura

Y por lo demás no hay demasiado misterio

Comentario

Al final implementar una técnica masonry sea cual sea la versión que escojas va a ser algo ofuscado

Pero no hay como practicar para ir interiorizando conceptos, y que lo que te parecía negro termine siendo un pálido agradable

🙋‍♂️

Qué tal el curso?
👌 Bien 🙌🙌
👍 Bien, pero algunas cosas podrían explicarse mejor 😬
🤷‍♂️ Da por sentadas demasiadas cosas 😒
🤷‍♂️ A ver, hay poca chicha 😬
🤷‍♂️ Los ejemplos no son muy claros 🙇‍♂️
🤷‍♂️ No se entiende, está mal escrito 👎
✍️ Hay errores, revísalo en cuanto puedas 🙏

Quizá te interese

Privacidad
by kuworking.com
[ 2020 >> kuworking ]