Gente de la Safor

Bienvenidos a Spain News Today.

Una guía práctica para crear componentes de reacción reutilizables

Aunque React es uno de los frameworks front-end más populares y más utilizados del mundo, muchos desarrolladores todavía luchan cuando se trata de refactorizar para mejorar la reutilización. Si repite el mismo fragmento de código en toda su aplicación React, ha llegado al artículo correcto.

En este tutorial, aprenderá sobre los tres indicadores más comunes de que es hora de crear un componente React reutilizable. Luego, echaremos un vistazo a algunas demostraciones prácticas mediante la creación de un diseño reutilizable y un par de interesantes ganchos de React.

Cuando termine de leer, podrá averiguarlo por sí mismo. cuando Es conveniente crear componentes React reutilizables y Como hacer Vamos a hacerlo.

Este artículo asume conocimientos básicos de React y React hooks. Si desea familiarizarse con estos temas, le recomiendo que consulte «Empezando con React«manual y»Intorducción para la interacción de ganchos«.

Tres indicaciones principales para un componente de reacción reutilizable

Primero veamos algunos consejos cuando Es posible que desee hacerlo.

Creación recursiva de envoltorios en el mismo estilo CSS

Mi señal favorita de saber cuándo crear un componente reutilizable es el uso frecuente del mismo estilo CSS. Ahora, podría pensar, «Espere un minuto: ¿por qué no simplemente asigno el mismo nombre de clase a los elementos que comparten el mismo estilo CSS?» Estás absolutamente en lo correcto. No es una buena idea crear componentes reutilizables cada vez que algunos elementos comparten diferentes componentes en el mismo patrón. De hecho, puede provocar complicaciones innecesarias. Entonces tienes que preguntarte una cosa más: ¿estos elementos son comunes en el diseño? cubre?

Por ejemplo, considere las siguientes páginas de inicio de sesión y registro:


import './common.css';

function Login() {
  return (
    <div className='wrapper'>
      <main>
        {...}
      </main>
      <footer className='footer'>
        {...}
      </footer>
    </div>
  );
}

import './common.css';

function Signup() {
  return (
    <div className='wrapper'>
      <main>
        {...}
      </main>
      <footer className='footer'>
        {...}
      </footer>
    </div>
  );
}

Se aplican los mismos estilos al contenedor (archivo. <div> componente) y el pie de página de cada componente. Entonces, en este caso, puede crear dos componentes reutilizables: <Wrapper /> Y <Footer /> – Y pasarles a los niños como apoyo. Por ejemplo, el componente de inicio de sesión se puede reconstruir de la siguiente manera:


import Footer from "./Footer.js";

function Login() {
  return (
    <Wrapper main={{...}} footer={<Footer />} />
  );
} 

Como resultado, ya no necesita importar common.css En varias páginas o crea lo mismo <div> Los elementos envuelven todo.

Uso frecuente de detectores de eventos

Para adjuntar un detector de eventos a un elemento, puede procesarlo desde dentro useEffect() como el:


import { useEffect } from 'react';

function App() {
  const handleKeydown = () => {
    alert('key is pressed.');
  }

  useEffect(() => {
    document.addEventListener('keydown', handleKeydown);
    return () => {
      document.removeEventListener('keydown', handleKeydown);
    }
  }, []);

  return (...);
}

O puede hacerlo directamente dentro de su JSX de esta manera, como se muestra en el siguiente componente de botón:


function Button() {
  return (
    <button type="button" onClick={() => { alert('Hi!')}}>
      Click me!
    </button>
  );
};

Cuando desee agregar un detector de eventos a document o window, tienes que seguir el primer método. Sin embargo, como ya se habrá dado cuenta, el primer método requiere más código con useEffect()Y addEventListener() Y removeEventListener(). Entonces, en tal caso, la creación de un gancho personalizado permitirá que sus componentes sean más concisos.

Hay cuatro escenarios posibles para usar detectores de eventos:

  • Mismo detector de eventos, mismo controlador de eventos
  • Mismo detector de eventos, controlador de eventos diferente
  • Oyente de eventos diferente, mismo controlador de eventos
  • Oyente de eventos diferente, manejador de eventos diferente

En el primer escenario, puede crear un enlace donde se definen tanto el detector de eventos como el controlador de eventos. Considere el siguiente gancho:


import { useEffect } from 'react';

export default function useKeydown() {
  const handleKeydown = () => {
    alert('key is pressed.');
  }

  useEffect(() => {
    document.addEventListener('keydown', handleKeydown);
    return () => {
      document.removeEventListener('keydown', handleKeydown);
    }
  }, []);
};

Luego puede usar este gancho en cualquier componente de la siguiente manera:


import useKeydown from './useKeydown.js';

function App() {
  useKeydown();
  return (...);
};

Para los otros tres escenarios, recomendaría crear un gancho que reciba un evento y una función de manejo de eventos como accesorios. Por ejemplo, ordenaré keydown Y handleKeydown Como soportes para mi gancho personalizado. Considere el siguiente gancho:


import { useEffect } from 'react';

export default function useEventListener({ event, handler} ) {
  useEffect(() => {
    document.addEventListener(event, props.handler);
    return () => {
      document.removeEventListener(event, props.handler);
    }
  }, []);
};

Luego puede usar este gancho en cualquier componente de la siguiente manera:


import useEventListener from './useEventListener.js';

function App() {
  const handleKeydown = () => {
    alert('key is pressed.');
  }
  useEventListener('keydown', handleKeydown);
  return (...);
};

Uso repetido del mismo script GraphQL

Realmente no necesita buscar etiquetas cuando se trata de hacer que el código GraphQL sea reutilizable. Para aplicaciones complejas, los scripts GraphQL para una consulta o mutación toman fácilmente de 30 a 50 líneas de código porque hay muchos atributos para ordenar. Si usa el mismo script GraphQL más de una o dos veces, creo que vale la pena su enlace personalizado.

Considere el siguiente ejemplo:

import { gql, useQuery } from "@apollo/react-hooks";

const GET_POSTS = gql`
  query getPosts {
    getPosts {
    user {
      id
      name
      ...
      }
      emojis {
         id
         ...
      }
      ...
  }
`;

const { data, loading, error } = useQuery(GET_POSTS, {
  fetchPolicy: "network-only"
});

En lugar de repetir este código en cada página que solicita publicaciones desde el back-end, debe crear un enlace de React para esta API:

import { gql, useQuery } from "@apollo/react-hooks";

function useGetPosts() {
  const GET_POSTS = gql`{...}`;
  const { data, loading, error } = useQuery(GET_POSTS, {
    fetchPolicy: "network-only"
  });
  return [data];
}

const Test = () => {
  const [data] = useGetPosts();
  return (
    <div>{data?.map(post => <h1>{post.text}</h1>)}</div>
  );
};

Construyendo tres componentes de reacción reutilizables

Ahora que hemos visto algunos signos comunes de cuando Para crear un nuevo componente que pueda compartir a través de su aplicación de interacción, pongamos este conocimiento en práctica y construyamos tres demostraciones prácticas.

1. Componente de planificación

React se usa a menudo para crear aplicaciones web complejas. Esto significa que es necesario desarrollar una gran cantidad de páginas en React, y dudo que cada página de la aplicación tenga un diseño diferente. Por ejemplo, una aplicación web de 30 páginas normalmente utiliza menos de cinco diseños diferentes. Por lo tanto, es necesario crear un diseño flexible y reutilizable que se pueda utilizar en muchas páginas diferentes. Esto le ahorrará una gran cantidad de líneas de código y, por lo tanto, una gran cantidad de tiempo.

Considere el siguiente componente funcional de React:


import React from "react";
import style from "./Feed.module.css";

export default function Feed() {
  return (
    <div className={style.FeedContainer}>
      <header className={style.FeedHeader}>Header</header>
      <main className={style.FeedMain}>
        {
          <div className={style.ItemList}>
            {itemData.map((item, idx) => (
              <div key={idx} className={style.Item}>
                {item}
              </div>
            ))}
          </div>
        }
      </main>
      <footer className={style.FeedFooter}>Footer</footer>
    </div>
  );
}

const itemData = [1, 2, 3, 4, 5];

Esta es una página web típica con la extensión <header>, a <main> y <footer>. Si hay 30 páginas web más como esta, se cansará fácilmente de escribir etiquetas HTML repetidamente y aplicar el mismo estilo una y otra vez.

Alternativamente, puede crear un componente de diseño que reciba <header>Y <main> Y <footer> Como accesorios, como en el siguiente código:


import React from "react";
import style from "./Layout.module.css";
import PropTypes from "prop-types";

export default function Layout({ header, main, footer }) {
  return (
    <div className={style.Container}>
      <header className={style.Header}>{header}</header>
      <main className={style.Main}>{main}</main>
      <footer className={style.Footer}>{footer}</footer>
    </div>
  );
}

Layout.propTypes = {
  main: PropTypes.element.isRequired,
  header: PropTypes.element,
  footer: PropTypes.element
};

Este componente no requiere <header> Y <footer>. Por lo tanto, puede utilizar este mismo diseño para las páginas independientemente de si tienen encabezado o pie de página.

Con este componente de diseño, puede convertir su página de feed en un bloque de código más complejo:


import React from "react";
import Layout from "./Layout";
import style from "./Feed.module.css";

export default function Feed() {
  return (
    <Layout
      header={<div className={style.FeedHeader}>Header</div>}
      main={
        <div className={style.ItemList}>
          {itemData.map((item, idx) => (
            <div key={idx} className={style.Item}>
              {item}
            </div>
          ))}
        </div>
      }
      footer={<div className={style.FeedFooter}>Footer</div>}
    />
  );
}

const itemData = [1, 2, 3, 4, 5];

Consejo profesional para crear diseños con elementos adhesivos

Muchos desarrolladores tienden a usar archivos. position: fixed o position: absolute Cuando quieran pegar un encabezado en la parte superior de la ventana gráfica o un pie de página en la parte inferior. Sin embargo, en el caso de los diseños, debe intentar evitarlo.

Dado que los elementos de diseño serán los elementos originales de los accesorios pasados, desea mantener el estilo de sus elementos de diseño lo más simple posible, de modo que los pases <header>Y <main>, o <footer> Como era la intención. Entonces, recomiendo la aplicación position: fixed Y display: flex Al elemento externo en planificación y preparación overflow-y: scroll a mi <main> un artículo.

Esto es un ejemplo:


.Container {
  
  display: flex;
  flex-direction: column;

  
  width: 100%;
  height: 100%;

  
  overflow: hidden;
  position: fixed;
}

.Main {
  
  width: 100%;
  height: 100%;

  
  overflow-y: scroll;
}

Ahora, apliquemos algunos estilos a su página de noticias y veamos lo que ha creado:


.FeedHeader {
  
  height: 70px;

  
  background-color: teal;
  color: beige;
}

.FeedFooter {
  
  height: 70px;

  
  background-color: beige;
  color: teal;
}

.ItemList {
  
  display: flex;
  flex-direction: column;
}

.Item {
  
  height: 300px;

  
  color: teal;
}

.FeedHeader,
.FeedFooter,
.Item {
  
  display: flex;
  justify-content: center;
  align-items: center;

  
  border: 1px solid teal;

  
  font-size: 35px;
}

Mostrar encabezado y pie de página fijados

Aquí está el código en acción.

Así es como se ve en las pantallas de escritorio.

escritorio

Así es como se ve en las pantallas de los móviles.

Mobile_Layout

¡Este diseño también funciona según lo previsto en dispositivos iOS! En caso de que no lo supiera, iOS es conocido por causar problemas inesperados relacionados con la ubicación para el desarrollo de aplicaciones web.

2. oyente de eventos

A menudo, el mismo detector de eventos se usa más de una vez en una aplicación web. En tal caso, es una buena idea crear un gancho React personalizado. Aprendamos a hacerlo desarrollando un archivo useScrollSaver El gancho, que guarda la posición de desplazamiento del dispositivo del usuario en la página, por lo que el usuario no necesita desplazarse de nuevo desde la parte superior. Este gancho será útil para una página web en la que se enumeran una gran cantidad de elementos, como publicaciones y comentarios; Imagine páginas de alimentación en Facebook, Instagram y Twitter sin guardar el desplazamiento.

Analicemos el siguiente código:


import { useEffect } from "react";

export default function useScrollSaver(scrollableDiv, pageUrl) {
  
  const handleScroll = () => {
    sessionStorage.setItem(
      `${pageUrl}-scrollPosition`,
      scrollableDiv.current.scrollTop.toString()
    );
  };
  useEffect(() => {
    if (scrollableDiv.current) {
      const scrollableBody = scrollableDiv.current;
      scrollableBody.addEventListener("scroll", handleScroll);
      return function cleanup() {
        scrollableBody.removeEventListener("scroll", handleScroll);
      };
    }
  }, [scrollableDiv, pageUrl]);

  
  useEffect(() => {
    if (
      scrollableDiv.current &&
      sessionStorage.getItem(`${pageUrl}-scrollPosition`)
    ) {
      const prevScrollPos = Number(
        sessionStorage.getItem(`${pageUrl}-scrollPosition`)
      );
      scrollableDiv.current.scrollTop = prevScrollPos;
    }
  }, [scrollableDiv, pageUrl]);
}

Puedes ver que un archivo useScrollSaver El gancho necesita recibir dos elementos: scrollableDiv, que debería ser un contenedor desplazable como un archivo <main> contenedor en el diseño anterior, y pageUrl, que se utilizará como identificador de página para que pueda almacenar posiciones de desplazamiento para varias páginas.

Paso 1: guarde la posición de desplazamiento

En primer lugar, debe vincular el detector de eventos ‘scroll’ a su contenedor desplazable:

const scrollableBody = scrollableDiv.current;
scrollableBody.addEventListener("scroll", handleScroll);
return function cleanup() {
  scrollableBody.removeEventListener("scroll", handleScroll);
};

Ahora, cada vez scrollableDiv Lo pasa un usuario, llamado función handleScroll Funcionará. En esta función, debes usar cualquiera de ellos localStorage o sessionStorage Para guardar la posición de desplazamiento. La diferencia es que los datos en localStorage No caduca, mientras los datos están en sessionStorage Se borra cuando finaliza la sesión de la página. puedes usar setItem(id: string, value: string) Para guardar datos en cualquier almacenamiento:

const handleScroll = () => {
  sessionStorage.setItem(
    `${pageUrl}-scrollPosition`,
    scrolledDiv.current.scrollTop.toString()
  );
};

Paso 2: restaura la posición de desplazamiento

Cuando el usuario regresa a la página web, se debe dirigir al usuario a la posición de desplazamiento anterior, si corresponde. Estos datos de posición se guardan actualmente en formato. sessionStorage, y debes sacarlo y usarlo. puedes usar getItem(id: string) Para obtener datos del almacenamiento. Después de eso, simplemente necesita ajustar scroll-top Desde el contenedor desplazable a este valor obtenido:

const prevScrollPos = Number(
  sessionStorage.getItem(`${pageUrl}scrollPosition`)
);
scrollableDiv.current.scrollTop = prevScrollPos;

Paso 3: utilizar useScrollSaver Enlace a cualquier página web

Ahora que ha terminado de crear su gancho personalizado, puede usar el gancho en cualquier página web que desee siempre que pase los dos elementos requeridos al gancho: scrollableDiv Y pageUrl. Volvamos a Layout.js Y usa tu gancho allí. Esto permitirá que cualquier página web que use este diseño disfrute de su portapapeles de desplazamiento:


import React, { useRef } from "react";
import style from "./Layout.module.css";
import PropTypes from "prop-types";
import useScrollSaver from "./useScrollSaver";

export default function Layout({ header, main, footer }) {
  const scrollableDiv = useRef(null);
  useScrollSaver(scrollableDiv, window.location.pathname);
  return (
    <div className={style.Container}>
      <header className={style.Header}>{header}</header>
      <main ref={scrollableDiv} className={style.Main}>
        {main}
      </main>
      <footer className={style.Footer}>{footer}</footer>
    </div>
  );
}

Versión de prueba de Scrollsaver

Y aquí está el código que se ejecuta en el Sandbox. Intente desplazarse por la página, luego use la flecha en la esquina inferior izquierda para volver a cargar la aplicación.

¡Te encontrarás justo donde lo dejaste!

3. Consulta / mutación (específico para GraphQL)

Si desea usar GraphQL con React, como lo hago yo, puede reducir su base de código aún más creando un gancho React para consultas o mutaciones GraphQL.

Considere el siguiente ejemplo de ejecución de una consulta GraphQL getPosts():

import { gql, useQuery } from "@apollo/react-hooks";

const GET_POSTS = gql`
  query getPosts {
    getPosts {
    user {
      id
      name
      ...
      }
      emojis {
         id
         ...
      }
      ...
  }
`;

const { data, loading, error } = useQuery(GET_POSTS, {
  fetchPolicy: "network-only"
});

Si hay más y más atributos para solicitar desde el back-end, el script GraphQL ocupará más espacio. Entonces, en lugar de repetir el script GraphQL y useQuery Cada vez que necesite ejecutar la consulta getPosts(), puede crear el siguiente gancho de React:


import { gql, useQuery } from "@apollo/react-hooks";

export default function useGetPosts() {
  const GET_POSTS = gql`
  query getPosts {
    getPosts {
    user {
      id
      name
      ...
      }
      emojis {
         id
         ...
      }
      ...
  }
  `;

  const { data, loading, error } = useQuery(GET_POSTS, {
    fetchPolicy: "network-only"
  });

  return [data, loading, error];
}

Después de eso, puedes usar un archivo useGetPosts() Conéctese de la siguiente manera:


import React from "react";
import Layout from "./Layout";
import style from "./Feed.module.css";
import useGetPosts from "./useGetPosts.js";

export default function Feed() {
  const [data, loading, error] = useGetPosts();
  return (
    <Layout
      header={<div className={style.FeedHeader}>Header</div>}
      main={
        <div className={style.ItemList}>
          {data?.getPosts.map((item, idx) => (
            <div key={idx} className={style.Item}>
              {item}
            </div>
          ))}
        </div>
      }
      footer={<div className={style.FeedFooter}>Footer</div>}
    />
  );
}

conclusión

En este artículo, aprendí los tres consejos más populares sobre el componente reutilizable de React y los tres casos de uso más populares. Ahora tienes el conocimiento cuando Para crear un componente React reutilizable y Como hacer Para hacer esto fácil y profesionalmente. Pronto se encontrará disfrutando de la refactorización de líneas de código en un componente React o un gancho reutilizable avanzado. Usando estas técnicas de reconstrucción, nuestro equipo de desarrollo en Arcilla Pudo reducir nuestra base de cuchillas a un tamaño manejable. ¡Espero que tú también puedas!