Saltar al contenido principal

Crear un frontend para tu dapp usando React

Esta sección explica cómo los frontends de tu dapp pueden interactuar con los contratos de ejemplo y acceder a datos de la cadena, además de conectarse a una billetera freighter. Esto se ilustrará utilizando bibliotecas proporcionadas por @soroban-react, un marco simple y poderoso para desarrollar Dapps modernas usando React. @soroban-react fue creada y es mantenida por un increíble miembro de la comunidad!

información

Esta guía demostrará cómo se desarrolló un frontend de un dapp de crowdfunding de ejemplo con React. Aunque gran parte del código es específico para este proyecto, los principios demostrados deberían ser lo suficientemente educativos para ayudarte a comenzar.

A continuación se muestra una lista de las bibliotecas utilizadas a lo largo del código del frontend y sus respectivas importaciones:

import { SorobanReactProvider } from "@soroban-react/core";
import { testnet, sandbox, standalone } from "@soroban-react/chains";
import { freighter } from "@soroban-react/freighter";
import { ChainMetadata, Connector } from "@soroban-react/types";
import type {
WalletChain,
ChainMetadata,
ChainName,
} from "@soroban-react/types";
import { useSorobanReact } from "@soroban-react/core";

Estas importaciones incluyen SorobanReactProvider de @soroban-react/core, que es un proveedor de contexto utilizado para pasar la instancia de SorobanReact a otros componentes. También importas varios tipos como WalletChain, ChainMetadata y ChainName, que ayudan a mantener la seguridad de tipos dentro de nuestra aplicación.

Componentes de React y Pasaje de Props

React prospera en su arquitectura basada en componentes. Los componentes son piezas reutilizables de código que devuelven un elemento de React para ser renderizado en la página. Una aplicación típica de React consiste en múltiples componentes que trabajan en armonía para crear una interfaz de usuario dinámica.

Miremos un componente del dapp de crowdfunding de ejemplo, el componente MintButton:

function MintButton({
account,
decimals,
symbol,
}: {
account: string;
decimals: number;
symbol: string;
}) {
const [isSubmitting, setSubmitting] = useState(false);
const { activeChain, server } = useNetwork();
const networkPassphrase = activeChain?.networkPassphrase ?? "";
const { sendTransaction } = useSendTransaction();
const amount = BigNumber(100);

return <Button props omitted here />;
}

Este componente funcional toma tres propiedades como argumentos: account, decimals y symbol. Demuestra el concepto de paso de props, una forma de pasar datos de componentes padre a hijo en React. La prop onComplete incluso te permite pasar funciones a tus componentes como props. También vemos el hook useState de React para la gestión del estado local, un método para preservar valores entre llamadas a funciones.

Gestión del Estado y Hooks

La gestión del estado es otro concepto central de React, permitiendo que los componentes creen y manejen sus propios datos. El useState hook es una característica introducida en React 16.8 que permite a los componentes funcionales tener su propio estado.

En el componente MintButton, el hook useState se utiliza para gestionar el estado isSubmitting:

const [isSubmitting, setSubmitting] = useState(false);

El hook useState devuelve un par de valores: el estado actual y una función que lo actualiza. En este caso, el estado isSubmitting se inicializa en false y la función setSubmitting se utiliza para actualizarlo. React también permite la creación de hooks personalizados, como useNetwork y useSendTransaction, para encapsular y reutilizar lógica con estado en múltiples componentes.

Hooks Personalizados

Los hooks de React son funciones que te permiten “conectar” con el estado de React y las características del ciclo de vida desde componentes funcionales. Los hooks personalizados te permiten encapsular lógica compleja y hacerla reutilizable en componentes. Miremos a useNetwork y useSendTransaction, dos hooks personalizados utilizados en el dapp de crowdfunding de ejemplo.

El hook useNetwork se utiliza para interactuar con la red de blockchain, y el hook useSendTransaction se usa para despachar transacciones. Estos hooks abstraen lógica compleja, facilitando la lectura y comprensión del código principal del componente.

Así es como usas estos hooks en el componente MintButton:

const { activeChain, server } = useNetwork();
const networkPassphrase = activeChain?.networkPassphrase ?? "";
const { sendTransaction } = useSendTransaction();

useNetwork proporciona la cadena activa y el servidor, y useSendTransaction nos da el método sendTransaction, que usarás más tarde para acuñar tokens. De esta manera, puedes mantener el componente enfocado en la renderización y la lógica de manejo de eventos, facilitando su prueba y mantenimiento.

Procesamiento Asincrónico y Manejo Robusto de Errores

Al tratar con operaciones que pueden tomar un tiempo impredecible, como peticiones de red o, en nuestro caso, acuñar tokens en la blockchain, el soporte de React para operaciones asincrónicas es crucial. Esto permite la ejecución del resto del código sin ser bloqueado por estas operaciones.

Adentrémonos en el fragmento de código que maneja el proceso de acuñación asincrónica:

try {
console.log("Minting the token...");
const paymentResult = await sendTransaction(
new SorobanClient.TransactionBuilder(adminSource, {
networkPassphrase,
fee: "1000",
})
.setTimeout(10)
.addOperation(
SorobanClient.Operation.payment({
destination: walletSource.accountId(),
asset: new SorobanClient.Asset(symbol, Constants.TokenAdmin),
amount: amount.toString(),
}),
)
.build(),
{
timeout: 10 * 1000,
skipAddingFootprint: true,
secretKey: Constants.TokenAdminSecretKey,
sorobanContext,
},
);
console.debug(paymentResult);
sorobanContext.connect();
} catch (err) {
console.log("Error while minting the token: ", err);
console.error(err);
}

Este bloque es donde ocurre la acuñación real de tokens. Está envuelto en un bloque try-catch, asegurando que cualquier error durante el proceso de acuñación sea capturado y manejado adecuadamente, evitando que la aplicación se bloquee y dándote la oportunidad de proporcionar retroalimentación al usuario.

La palabra clave await pausa la ejecución de la función hasta que la promesa devuelta por sendTransaction se resuelva. sendTransaction es una función obtenida de nuestro hook useSendTransaction, y construye y envía una operación de pago a la red Stellar.

El método sendTransaction acepta dos argumentos: una instancia de TransactionBuilder y un objeto de opciones. El TransactionBuilder establece los detalles de la transacción, como la cuenta de origen, la frase de red, la tasa de transacción y las operaciones a realizar—en este caso, una operación de pago.

Si la transacción tiene éxito, paymentResult contiene el resultado, que registras para fines de depuración. Si ocurre un error durante la transacción, la función lanza un error, el cual capturas y registras.

Conclusión

React ofrece una variedad de conceptos de alto nivel que pueden mejorar drásticamente tu proceso de desarrollo web. Al comprender y utilizar estos conceptos—como componentes, paso de props, gestión de estado, operaciones asincrónicas y manejo de errores—puedes crear aplicaciones escalables, mantenibles y eficientes.

Recuerda, la clave para dominar React es la práctica. ¡Así que sigue construyendo y experimentando!