hand Inicio
hand JSBloqs
hand GutenBloqs
Qu茅?
noched铆a

DESARROLLO WEB con
REACT y WORDPRESS

Ap煤ntate a la newsletter (escribo algo de tanto en cuanto)

Ordenar listas con JavaScript, sort(), React y un custom hook

500 palabras
2 minutos
July 10, 2020
blogjavascript

Ordenar listas es f谩cil con sort(), y con con React tambi茅n es f谩cil con useState(), y si adem谩s queremos reutilizar la rutina para siempre, m谩s que f谩cil con un custom hook

  1. Funci贸n sort()
  2. Opci贸n 1: Sin custom hooks, una funci贸n al uso
  3. Opci贸n 2: Con un custom hook

Funci贸n sort()

Para ordenar listas, nada m谩s sencillo que utilizar la funci贸n sort(), que funciona (puedes mirarlo aqu铆) simplemente comparando valores:

js
const lista = [2, 5, 4, 7]
console.log(lista.sort())
// [2, 4, 5, 7]

Esto de arriba es lo mismo que hacer lo siguiente

js
const lista = [2, 5, 4, 7]
console.log(lista.sort((a, b) => a - b))
// [2, 4, 5, 7]

sort() invoca una funci贸n que recibe dos valores, y estos son los que compararemos

Si no son n煤meros y queremos un orden alfab茅tico, har铆amos lo siguiente

js
const lista = ['juan', 'palomo', 'y', 'sus cosas']
console.log(
lista.sort((a, b) => {
if (a > b) return 1
if (a < b) return -1
return 0
})
)
// ["juan", "palomo", "sus cosas", "y"]

Pero no hace falta escribir tanto, podemos expresar lo mismo con una l铆nea

js
const lista = ['juan', 'palomo', 'y', 'sus cosas']
console.log(lista.sort((a, b) => (a > b ? 1 : a < b ? -1 : 0)))
// ["juan", "palomo", "sus cosas", "y"]

Y si lo que tenemos son estructuras complejas, pues lo mismo

js
const lista = [
{ nombre: 'juan', edad: 50 },
{ nombre: 'alberto', edad: 40 },
{ nombre: 'aragor', edad: 2000 },
]
console.log(lista.sort((a, b) => (a.edad > b.edad ? 1 : a.edad < b.edad ? -1 : 0)))
// 0: {nombre: "alberto", edad: 40}
// 1: {nombre: "juan", edad: 50}
// 2: {nombre: "aragor", edad: 2000}

Bien

El tema es, y si esta lista la queremos mostrar en el front end?

Ning煤n problema, con React es tan sencillo como utilizar un estado, y en cuanto actualicemos el estado por lo que sea (un bot贸n que se clicke, o simplemente al principio de todo) pues la lista se re-renderizar谩 sola

Har茅 las dos cosas, que se ordene al principio de todo y con un bot贸n, y con el bot贸n cada vez la ordenar茅 al rev茅s de lo que estaba

La funci贸n sort me muta el array, es decir que me modifica el array en lugar de devolver uno nuevo

Para evitarlo hago una copia del array antes de aplicar sort

La raz贸n es porque cambiar los objetos acostumbra a ser un generador de bugs

jsx
import React, { useState, useEffect } from 'react'
// mi componente principal <Lista>
const Lista = () => {
// guardo el estado list de valor inicial la lista que tengo
const [list, setList] = useState([
{ nombre: 'juan', edad: 50 },
{ nombre: 'alberto', edad: 40 },
{ nombre: 'aragor', edad: 2000 },
])
// utilizo useEffect para ejecutar este c贸digo s贸lo una vez
useEffect(() => {
// copio la lista con [...list] y la ordeno con sort()
const sortedList = [...list].sort((a, b) => (a.edad > b.edad ? 1 : a.edad < b.edad ? -1 : 0))
// actualizo el estado con la nueva lista ya ordenada
setList(sortedList)
}, [])
// vuelco el contenido del estado `list`
return (
<>
{/* Aqu铆 pongo el bot贸n para reordenar la lista */}
<button
onClick={() => {
let newSortedList = [...list].sort((a, b) => (a.edad > b.edad ? 1 : a.edad < b.edad ? -1 : 0))
// si la lista despu茅s de ordenarla tiene el mismo primer elemento, lo repito a la inversa
// (claro que esto es ineficiente, lo suyo ser铆a habilitar otro estado para guardar el tipo de ordenamiento que hemos hecho)
if (newSortedList[0] === list[0])
newSortedList = [...list].sort((b, a) => (a.edad > b.edad ? 1 : a.edad < b.edad ? -1 : 0))
setList(newSortedList)
}}
>
Ordenar
</button>
{/* Y aqu铆 la lista, cada vez que el estado cambie este componente se va a repintar y a actualizar la vista */}
<ul>
{list.map(el => (
<li>
{el.nombre}: {el.edad}
</li>
))}
</ul>
</>
)
}
export default Lista
Ver en CodeSandBox

Listos! Ya estamos ordenando a la manera React, nada de tocar el DOM sino trabajar con datos, actualizar los datos, y dejar que React actualize el DOM cuando estos datos cambien

Y si queremos reaprovechar esta funci贸n?

Para eso tenemos los custom hooks, que no son m谩s que maneras de encapsular c贸digo para que su reutilizaci贸n sea la mar de c贸moda

Opci贸n 1: Sin custom hooks, una funci贸n al uso

jsx
import React, { useState, useEffect } from 'react'
// Esta es mi funci贸n para reutilizar `sort`
const sort_lists = (key, list, inverse) =>
inverse
? [...list].sort((b, a) => (a[key] > b[key] ? 1 : a[key] < b[key] ? -1 : 0))
: [...list].sort((a, b) => (a[key] > b[key] ? 1 : a[key] < b[key] ? -1 : 0))
// Y este mi componente principal
const Lista = () => {
const [list, setList] = useState([
{ nombre: 'juan', edad: 50 },
{ nombre: 'alberto', edad: 40 },
{ nombre: 'aragor', edad: 2000 },
])
useEffect(() => {
setList(sort_lists('edad', list))
}, [])
return (
<>
<button
onClick={() => {
let newSortedList = sort_lists('edad', list)
if (newSortedList[0] === list[0]) newSortedList = sort_lists('edad', list, true)
setList(newSortedList)
}}
>
Ordenar
</button>
<ul>
{list.map(el => (
<li>
{el.nombre}: {el.edad}
</li>
))}
</ul>
</>
)
}
export default Lista
Ver en CodeSandBox

Ahora si queremos reordenar listas, basta con que copiemos la funci贸n sort_lists() en nuestro c贸digo y ya lo tendremos

Eso s铆, en realidad hemos encapsulado exclusivamente la funcionalidad para ordenar listas

En el c贸digo seguimos necesitando implantar la l贸gica de utilizar un useEffect para ordenar la lista al principio, y un useState para guardar la lista en un estado

Y si pudi茅semos tambi茅n encapsular esta l贸gica?

S铆 que podemos, vamos con el custom hook

Opci贸n 2: Con un custom hook

En lugar de definir una funci贸n, definimos un hook que como tal tiene que empezar con el useLoQueSea

jsx
import React, { useState, useEffect } from 'react'
// Este es mi custom hook
const useSortTable = (listToSort, originalKey) => {
// definimos un estado
const [list, setList] = useState(listToSort)
// definimos la funci贸n anterior pero sin especificar la lista ya que ser谩 la principal
const sort_lists = (key, inverse) =>
inverse
? [...list].sort((b, a) => (a[key] > b[key] ? 1 : a[key] < b[key] ? -1 : 0))
: [...list].sort((a, b) => (a[key] > b[key] ? 1 : a[key] < b[key] ? -1 : 0))
// ordenamos la lista con el useEffect
useEffect(() => {
setList(sort_lists(originalKey))
}, [])
// devolvemos el estado que contiene la lista
// ..el m茅todo para actualizar el estado
// ..y el m茅todo para ordenarla
return [list, setList, sort_lists]
}
// Ahora seguimos con el componente principal
const Lista = () => {
// y aqu铆 utilizamos el hook
const [list, setList, sort] = useSortTable(
[
{ nombre: 'juan', edad: 50 },
{ nombre: 'alberto', edad: 40 },
{ nombre: 'aragor', edad: 2000 },
],
'edad'
)
return (
<>
<button
onClick={() => {
let newSortedList = sort('edad')
if (newSortedList[0] === list[0]) newSortedList = sort('edad', true)
setList(newSortedList)
}}
>
Ordenar
</button>
<ul>
{list.map(el => (
<li>
{el.nombre}: {el.edad}
</li>
))}
</ul>
</>
)
}
export default Lista
Ver en CodeSandBox

Si te fijas ver谩s que el hook en realidad engloba la funci贸n de antes y tambi茅n la l贸gica del useEffect y useState

Qu茅 le falta a este c贸digo?

  • La l贸gica para invertir la b煤squeda es ineficiente

Si queremos un bot贸n que nos ordene para una direcci贸n o para otra, la manera es almacenar la direcci贸n en otro estado y en funci贸n de esto ordenarla de una manera u otra

Aqu铆 la estamos ordenando dos veces

  • La l贸gica para invertir la b煤squeda no est谩 bien integrada en el hook

Lo suyo ser铆a tener una funci贸n para invertir la b煤squeda y que esta funci贸n tambi茅n te actualizase el estado, algo tipo

js
<button onClick={sort}>Ordenar</button>

Se puede hacer sin problemas siempre que antes se solucione el problema anterior

  • La funci贸n list.map genera componentes que no tienen una key asociada, y por eso nos sale el warning de rigor

Hace falta a帽adir la key manualmente en estos casos

js
{
list.map((el, i) => (
<li key={`lista${i}`}>
{el.nombre}: {el.edad}
</li>
))
}

Listos!

馃檵鈥嶁檪锔

Qu茅 tal la entrada?

馃憣 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 馃檹
Enviar Feedback 鉁嶏笍
El texto est谩 en blanco!
Gracias por enviarme tu opini贸n
馃憤

Si quieres explorar m谩s cursos y m谩s entradas en el blog, los tienes todos en la p谩gina principal, y si el contenido te ha ayudado si lo compartes me ayudas a dar difusi贸n 馃憤

Privacidad
by kuworking.com
[ 2020 >> kuworking ]