Cómo crear un componente de lista Seleccionar todo en React con Next.js

Cómo crear un componente de lista de selección total usando React en una aplicación Next.js.

Primeros pasos

Para este tutorial, usaremos CheatCode Next.js Boilerplate para darnos un punto de partida para nuestro trabajo. Primero, clone el modelo:

Terminal

git clone https://github.com/cheatcode/nextjs-boilerplate.git

A continuación, cd en el proyecto e instalar sus dependencias:

Terminal

cd nextjs-boilerplate && npm install

A continuación, agregue la dependencia faker que usaremos para generar algunos datos de prueba realistas para nuestra lista de selección total:

Terminal

npm i faker

Finalmente, inicie la aplicación:

Terminal

npm run dev

Con la aplicación funcionando, estamos listos para comenzar.

Construyendo un componente base

Para comenzar, primero, vamos a crear un componente React básico. Debido a que nuestra interfaz de usuario es bastante simple, usaremos el patrón del componente de función en React:

/páginas/usuarios/index.js

import React, { useState } from "react";

const Users = () => {
  const [users] = useState([]);
  const [selectedUsers, setSelectedUsers] = useState([]);

  return (
    <div className="responsive-table">
      <table className="table">
        <thead>
          <tr>
            <th>
              <input
                type="checkbox"
              />
            </th>
            <th className="text-left">Name</th>
            <th className="text-left">Email Address</th>
            <th className="text-center">Last Seen</th>
          </tr>
        </thead>
        <tbody>
          {users.map(({ _id, name, emailAddress, lastSeen }) => {
            return (
              <tr key={_id}>
                <td>
                  <input
                    type="checkbox"
                    value={_id}
                  />
                </td>
                <td className="text-left">{name}</td>
                <td className="text-left">{emailAddress}</td>
                <td className="text-center">{lastSeen}</td>
              </tr>
            );
          })}
        </tbody>
      </table>
    </div>
  );
};

Users.propTypes = {};

export default Users;

Aquí, estamos configurando un componente React que generará un <table></table> de usuarios, y cada usuario obtiene una casilla de verificación que podemos usar para marcarlos como seleccionados en la primera columna de su fila. En el <thead></thead> de la tabla, añadimos un <input type="checkbox" /> que servirá como la casilla de verificación "seleccionar todo" para toda la lista.

En la parte superior de nuestro componente, usamos el useState() gancho función de React para crear dos valores dinámicos:una lista de users que renderizaremos en nuestro <tbody></tbody> y luego una lista de selectedUsers que usaremos para marcar las casillas de verificación en nuestra tabla para designar qué usuarios están actualmente seleccionados en la interfaz de usuario.

Por ahora, estamos configurando el valor predeterminado para estos en una matriz vacía (el [] que pasamos a useState() ). A continuación, para mostrar algunos usuarios en nuestra lista, aprenderemos cómo generar algunos datos de prueba sobre la marcha usando el faker dependencia que instalamos anteriormente.

Generando una lista de usuarios de prueba

Fuera de nuestro Users función componente, agreguemos una nueva variable, testUsers :

/páginas/usuarios/index.js

import React, { useState } from "react";
import faker from 'faker';
import { monthDayYearAtTime } from "../../lib/dates";

const testUsers = [...Array(100)].map((item, index) => {
  return {
    _id: `user_${index}`,
    name: faker.name.findName(),
    emailAddress: faker.internet.email(),
    lastSeen: monthDayYearAtTime(faker.date.past()),
  };
});

const Users = () => {
  const [users] = useState(testUsers);
  const [selectedUsers, setSelectedUsers] = useState([]);

  return (
    <div className="responsive-table">
      <table className="table">
        <thead>
          <tr>
            ...
          </tr>
        </thead>
        <tbody>
          {users.map(({ _id, name, emailAddress, lastSeen }) => {
            return (
              <tr key={_id}>
                ...
              </tr>
            );
          })}
        </tbody>
      </table>
    </div>
  );
};

Users.propTypes = {};

export default Users;

En la parte superior de nuestro archivo, hemos importado dos cosas:faker del faker dependencia que instalamos anteriormente y una función auxiliar integrada en el modelo que estamos usando monthDayYearAtTime lo que nos ayudará a generar una fecha de "última vista" fácil de usar para cada uno de nuestros usuarios.

A continuación, agregamos una nueva variable testUsers que se establece en una matriz vacía [] que contiene la sentencia ...Array(100) . Aquí, el ... se conoce como el operador de propagación en JavaScript. Esto toma el valor que le sigue inmediatamente, aquí, Array(100) —y lo esparce en el contexto principal o, en este caso, nuestra matriz vacía.

El Array(100) parte aquí es un buen truco usando JavaScript Array función para crear una matriz de 100 elementos. Al pasar el número 100, obtendremos una matriz de 100 undefined valores. Cada undefined valor se reconoce como un valor en JavaScript, lo que significa que, si .map() sobre esa matriz como si estuviéramos aquí, podemos tratar esos undefined valores como marcadores de posición y devolver un real valor en el .map() devolución de llamada de la función.

Aquí, hacemos exactamente eso, devolviendo un objeto para reemplazar el undefined creado por el Array(100) . En cada objeto, agregamos un _id igual a user_ concatenado con el índice de matriz actual (algún número de 0-99). Luego, usando el faker biblioteca que importamos arriba, generamos un nombre para el usuario con faker.name.findName() para recuperar una cadena de nombre completo y una dirección de correo electrónico con faker.internet.email() .

A continuación, configuramos un lastSeen marca de tiempo (principalmente por diversión y para que nuestro ejemplo sea más concreto), nuevamente usando faker para obtener una fecha aleatoria en el pasado con faker.date.past() . Pasamos esa fecha aleatoria al monthDayYearAtTime() función que importamos arriba para convertir la fecha que generamos en una cadena legible por humanos.

Finalmente, con nuestro testUsers valor generado, reemplazamos el [] que pasamos al useState() definición para nuestro users lista con nuestro nuevo testUsers variable. Ahora, cuando representemos nuestro componente, deberíamos ver una lista de nuestros usuarios de prueba en la pantalla.

Selección de usuarios individuales

Ahora que tenemos una lista de usuarios, podemos implementar la selección de usuarios. Nuestro objetivo es hacer que podamos hacer una de dos cosas:

  1. Seleccione y anule la selección de usuarios individuales de uno en uno.
  2. Seleccione o anule la selección de todos los usuarios a la vez.

Para manejar la primera opción, vamos a modificar el <input type="checkbox" /> para incluir un onChange controlador y una forma de establecer su checked estado:

/páginas/usuarios/index.js

import React, { useState } from "react";
import faker from "faker";
import { monthDayYearAtTime } from "../../lib/dates";

const testUsers = [...Array(100)].map((item, index) => { ... });

const Users = () => {
  const [users] = useState(testUsers);
  const [selectedUsers, setSelectedUsers] = useState([]);

  const handleSelectUser = (event) => {};

  return (
    <div className="responsive-table">
      <table className="table">
        <thead>
          ...
        </thead>
        <tbody>
          {users.map(({ _id, name, emailAddress, lastSeen }) => {
            return (
              <tr key={_id}>
                <td>
                  <input
                    type="checkbox"
                    value={_id}
                    checked={selectedUsers.includes(_id)}
                    onChange={handleSelectUser}
                  />
                </td>
                ...
              </tr>
            );
          })}
        </tbody>
      </table>
    </div>
  );
};

Users.propTypes = {};

export default Users;

Aquí, mirando el <input type="checkbox" /> representado al comienzo de cada fila de usuario, hemos agregado dos atributos:checked y onChange .

Para checked , lo establecemos igual a una expresión de JavaScript que toma nuestro selectedUsers valor de estado y, utilizando la matriz de JavaScript .includes() método, busca el _id del usuario que actualmente estamos mapeando en la lista. Si su _id aparece en esa matriz, eso significa que es un usuario seleccionado, o que su casilla de verificación debe aparecer "marcada".

A continuación, para el onChange , pasamos una función que hemos eliminado justo encima de nuestro return declaración llamada handleSelectUser . Siempre que la casilla de verificación esté marcada o desmarcada, se llamará a esta función. Configurémoslo ahora para manejar la administración del estado seleccionado de un usuario.

/páginas/usuarios/index.js

import React, { useState } from "react";
import faker from "faker";
import { monthDayYearAtTime } from "../../lib/dates";

const testUsers = [...Array(100)].map((item, index) => { ... });

const Users = () => {
  const [users] = useState(testUsers);
  const [selectedUsers, setSelectedUsers] = useState([]);

  const handleSelectUser = (event) => {
    const userId = event.target.value;

    if (!selectedUsers.includes(userId)) {
      setSelectedUsers([...selectedUsers, userId]);
    } else {
      setSelectedUsers(
        selectedUsers.filter((selectedUserId) => {
          return selectedUserId !== userId;
        })
      );
    }
  };

  return (
    <div className="responsive-table">
      <table className="table">
        <thead>
         ...
        </thead>
        <tbody>
          {users.map(({ _id, name, emailAddress, lastSeen }) => {
            return (
              <tr key={_id}>
                <td>
                  <input
                    type="checkbox"
                    value={_id}
                    checked={selectedUsers.includes(_id)}
                    onChange={handleSelectUser}
                  />
                </td>
                ...
              </tr>
            );
          })}
        </tbody>
      </table>
    </div>
  );
};

Users.propTypes = {};

export default Users;

Mirando el handleSelectUser función, empezamos tomando en el onChange objeto de evento como argumento, usándolo para recuperar el _id del usuario al que pertenece la casilla de verificación marcada con event.target.value y almacenarlo en una variable const userId .

A continuación, nuestro verdadero trabajo. Recuerde que hay dos escenarios a considerar:

  1. Un usuario no tenía su casilla de verificación marcada y debe agregarse al selectedUsers matriz.
  2. Un usuario ya tiene marcada su casilla de verificación y necesita ser eliminado del selectedUsers matriz.

Aquí, hacemos precisamente eso. Para el primer caso, verificamos si selectedUsers ya .includes() el userId sacamos de event.target.value . Si no , usamos el setSelectedUsers método que obtenemos de useState() , pasándole una matriz cuyo primer valor es un ... propagación del selectedUsers existente y un segundo valor del userId queremos agregar. A su vez, configuramos nuestra matriz de selectedUsers volver al estado, incluido el userId lo comprobamos.

Para el segundo escenario, aquí, en el else instrucción:llamamos a setSelectedUsers de nuevo, pero esta vez usa JavaScript .filter() método para filtrar nuestro selectedUsers matriz, excluyendo el marcado userId de la matriz. Aquí, selectedUserId !== userId solo evaluará a true si el userId no coincide con el selectedUserId actualmente en bucle en el .filter() .

Porque estamos pasando esto a setSelectedUsers() , obtendremos el selectedUsers filtrado establecer en el estado cuando esto se ejecuta.

Selección de todos los usuarios

A continuación, la selección de todos los usuarios requiere un enfoque similar, pero un poco más simple...

/páginas/usuarios/index.js

import React, { useState } from "react";
import faker from "faker";
import { monthDayYearAtTime } from "../../lib/dates";

const testUsers = [...Array(100)].map((item, index) => { ... });

const Users = () => {
  const [users] = useState(testUsers);
  const [selectedUsers, setSelectedUsers] = useState([]);

  const handleSelectAllUsers = () => {
    if (selectedUsers.length < users.length) {
      setSelectedUsers(users.map(({ _id }) => _id));
    } else {
      setSelectedUsers([]);
    }
  };

  const handleSelectUser = (event) => { ... };

  return (
    <div className="responsive-table">
      <table className="table">
        <thead>
          <tr>
            <th>
              <input
                type="checkbox"
                checked={selectedUsers.length === users.length}
                onChange={handleSelectAllUsers}
              />
            </th>
            <th className="text-left">Name</th>
            <th className="text-left">Email Address</th>
            <th className="text-center">Last Seen</th>
          </tr>
        </thead>
        <tbody>
          {users.map(({ _id, name, emailAddress, lastSeen }) => {
            return (
              <tr key={_id}>
                ...
              </tr>
            );
          })}
        </tbody>
      </table>
    </div>
  );
};

Users.propTypes = {};

export default Users;

Porque nuestro objetivo es seleccionar todos de nuestros usuarios, primero, en el <input type="checkbox" /> en nuestro <thead></thead> , configuramos el checked atributo igual a selectedUsers.length === users.length . Si esto es cierto, eso significa que hemos seleccionado todos los usuarios disponibles.

Nuevamente, como vimos antes, agregamos un onChange atributo establecido en una función, esta vez definiendo una nueva llamada handleSelectAllUsers .

Mirando esa función, tal como aprendimos antes, tenemos que manejar el estado no marcado -> marcado, así como el estado marcado -> no marcado. Para hacerlo aquí, para el primer caso, si selectedUsers.length es menor que users.length , nosotros setSelectedUsers igual a una nueva matriz creada por .map() sobre nuestro users matriz, arrancando el _id campo de cada usuario. Esto pone todos los _id de nuestros usuarios s en selectedUsers , lo que significa el selectedUsers.includes(userId) al lado de cada usuario será verdadero, mostrando al usuario como marcado.

A continuación, en el else declaración, el inverso aquí es tan fácil como llamar a setSelectedUsers() , pasándole una matriz vacía [] lo que significa que actualmente no hay ningún usuario seleccionado.

Terminando

En este tutorial, aprendimos cómo construir un componente de selección total usando React.js. Aprendimos a definir un componente de React que representa una tabla de usuarios generados dinámicamente, con una casilla de verificación para seleccionar junto a cada usuario y una casilla de verificación "seleccionar todo" en la parte superior de esa tabla.

También aprendimos a escribir dos funciones:una para seleccionar y anular la selección de usuarios individuales y otra para seleccionar y anular la selección de todos los usuarios.