Programación, Tecnología y Más...

Programación, Tecnología y Más...

Ionic-React Comunicación en Tiempo Real Backend Net Core(SignalR)

 Hace un par de meses te enseñé como poder hacer aplicaciones que se puedan comunicar en tiempo real desde el backend y frontend con un ejemplo de una api en net core  usando signalr y una aplicación con ionic-vue.

Pues bien esta vez volveremos a realizar el frontend usando ionic-react si aún no conoces ionic te recomiendo que le des una mirada a la documentación(que de hecho esta muy buena) ya que en mi opinión personal  me parece un gran framework con el cual puedes realizar casi todo tipo de aplicaciones(web, pwa, aplicaciones móviles híbridas).

Puedes ver la aplicacion que realizaremos desplegada en netlify https://ionic-react-netcore.netlify.app/

Lo primero que haremos será instalar el cli de ionic.

npm install -g @ ionic / cli
Creamos nuestra aplicación.
ionic start product-app-real-time tabs --type=react 
Una vez creado nuestro proyecto instalamos el paquete que nos servirá para establecer la comunicación con signalr
npm i @microsoft/signalr
Dentro de la carpeta src creamos un archivo api-endpoint.ts que solo tendrá una constante que representara la uri base de nuestra api para poder consumir los diferentes endpoints de la api
const url =  "https://products-api-signalr.herokuapp.com";
export default url;
Dentro de la carpeta pages modificamos el archivo Tab1.tsx
import {
	HubConnection,
	HubConnectionBuilder,
} from "@microsoft/signalr";
import "./Tab1.css";

import {
	IonContent,
	IonHeader,
	IonItem,
	IonLabel,
	IonList,
	IonListHeader,
	IonPage,
	IonTitle,
	IonToolbar,
} from "@ionic/react";

import { useEffect, useState } from "react";
import api from "../api-endpoint";
import { alertController } from "@ionic/core";

interface IProducts {
	id: number;
	category: string;
	name: string;
}

const Tab1: React.FC = () => {
	const [connection, setConnection] =
		useState<null | HubConnection>(null);
	const [products, setProducts] = useState([]);

	useEffect(() => {
		getData();
		//* connection hub backend
		const connect = new HubConnectionBuilder()
			.withUrl(`${api}/product-hub`)
			.withAutomaticReconnect()
			.build();

		setConnection(connect);
	}, []);

	useEffect(() => {
		//* show alert add product
		if (connection) {
			(async () => {
				try {
					await connection.start();
					console.log("SignalR Connected.");
					connection.on(
						"NewProduct",
						async (product: {
							name: string;
							category: string;
							price: number;
						}) => {
							const alert = await alertController.create({
								cssClass: "my-custom-class",
								header: "New Product",
								subHeader: product.name,
								message: JSON.stringify(
									product,
									null,
									"\t"
								),
								buttons: ["OK"],
							});
							await alert.present();

							getData();
						}
					);
				} catch (err) {
					console.log(err);
				}
			})();
		}
	}, [connection]);

	//method get data from api
	const getData = async () => {
		try {
			const response = await fetch(`${api}/api/product`);
			const dataApi = await response.json();
			setProducts(dataApi);
		} catch (error) {
			console.log(error);
		}
	};

	return (
		<IonPage>
			<IonHeader>
				<IonToolbar>
					<IonTitle>Home</IonTitle>
				</IonToolbar>
			</IonHeader>
			<IonContent fullscreen className="ion-padding">
				<IonHeader collapse="condense">
					<IonToolbar></IonToolbar>
				</IonHeader>
				<IonList>
					<IonListHeader lines="inset">
						<IonLabel>Products</IonLabel>
					</IonListHeader>
					{products.map(
						({ id, category, name }: IProducts) => (
							<IonItem key={id}>
								<IonLabel>
									<h2>{category}</h2>
									<h3>{name}</h3>
								</IonLabel>
							</IonItem>
						)
					)}
				</IonList>
			</IonContent>
		</IonPage>
	);
};

export default Tab1;
Lo interesante de ionic es que usa typescript lo cual nos permite tener más control sobre el código, el componente anterior representará nuestra página principal que será donde cargaremos los datos de la api es por eso que usamos los hooks useState y useEffect para poder pintar los datos en un componente tipo list que son de los muchos componentes que ionic nos ofrece, también en este archivo será donde realizaremos la conexión en tiempo real con signalR usando el paquete que instalamos anteriormente.

Ahora modificaremos el archivo Tab2.tsx
import { loadingController } from "@ionic/core";
import {
	IonButton,
	IonCol,
	IonContent,
	IonGrid,
	IonHeader,
	IonInput,
	IonItem,
	IonLabel,
	IonPage,
	IonRow,
	IonTitle,
	IonToolbar,
} from "@ionic/react";
import { ChangeEvent, useState } from "react";
import api from "../api-endpoint";
import "./Tab2.css";

type FormElement = ChangeEvent<HTMLInputElement>;

interface IProduct {
	name: string;
	category: string;
	price: number;
}

const initialForm = {
	name: "",
	category: "",
	price: 0,
};

const Tab2: React.FC = () => {
	const styles = {
		height: "100%",
	};

	const [form, setForm] = useState<IProduct>(initialForm);

	const handleChange = (e: FormElement) => {
		setForm({
			...form,
			[e.target.name]: e.target.value,
		});
	};

	const handleSubmit = async () => {
		if (form.name.length > 2) {
			const loading = await loadingController.create({
				cssClass: "my-custom-class",
				message: "Add...",
			});
			try {
				await loading.present();

				//post data api
				const requestOptions = {
					method: "POST",
					headers: { "Content-Type": "application/json" },
					body: JSON.stringify({
						name: form.name,
						category: form.category,
						price: form.price,
					}),
				};
				const response = await fetch(
					`${api}/api/product`,
					requestOptions
				);
				const data = await response.json();
				console.log(data);
				setForm(initialForm);
			} catch (error) {
				console.log(error);
			} finally {
				await loading.dismiss();
			}
		}
	};

	return (
		<IonPage>
			<IonHeader>
				<IonToolbar>
					<IonTitle>Add Products</IonTitle>
				</IonToolbar>
			</IonHeader>
			<IonContent fullscreen>
				<IonHeader collapse="condense">
					<IonToolbar>
						<IonTitle size="large">Tab 2</IonTitle>
					</IonToolbar>
				</IonHeader>
				<IonGrid style={styles}>
					<IonRow
						className="ion-justify-content-center ion-align-items-center"
						style={styles}
					>
						<IonCol
							size="12"
							size-xs="12"
							size-sm="6"
							size-md="6"
							size-lg="6"
						>
							<form
								onSubmit={e => {
									e.preventDefault();
									handleSubmit();
								}}
							>
								<IonItem>
									<IonLabel position="floating">
										Name
									</IonLabel>
									<IonInput
										name="name"
										onIonChange={(e: any) =>
											handleChange(e)
										}
										value={form.name}
									/>
								</IonItem>
								<IonItem>
									<IonLabel position="floating">
										Category
									</IonLabel>
									<IonInput
										name="category"
										onIonChange={(e: any) =>
											handleChange(e)
										}
										value={form.category}
									/>
								</IonItem>
								<IonItem>
									<IonLabel position="floating">
										Price
									</IonLabel>
									<IonInput
										type="number"
										name="price"
										onIonChange={(e: any) =>
											handleChange(e)
										}
										value={form.price}
									></IonInput>
								</IonItem>
								<div className="ion-text-center ion-padding-top">
									<IonButton
										type="submit"
										color="success"
										shape="round"
									>
										Add
									</IonButton>
								</div>
							</form>
						</IonCol>
					</IonRow>
				</IonGrid>
			</IonContent>
		</IonPage>
	);
};

export default Tab2;

Este componente representa la página donde insertaremos un nuevo producto así que con los componentes que ionic nos ofrece construimos un pequeño formulario para poder agregar productos a nuestra api.

Por último modificamos el archivo App.tsx que sera donde se configuran las rutas que tendra nuestra aplicación 
import { Redirect, Route } from "react-router-dom";
import {
	IonApp,
	IonIcon,
	IonRouterOutlet,
	IonTabBar,
	IonTabButton,
	IonTabs,
} from "@ionic/react";
import { IonReactRouter } from "@ionic/react-router";
import {
	addCircleOutline,
	informationCircleOutline,
	homeOutline,
} from "ionicons/icons";
import Tab1 from "./pages/Tab1";
import Tab2 from "./pages/Tab2";
import Tab3 from "./pages/Tab3";

/* Core CSS required for Ionic components to work properly */
import "@ionic/react/css/core.css";

/* Basic CSS for apps built with Ionic */
import "@ionic/react/css/normalize.css";
import "@ionic/react/css/structure.css";
import "@ionic/react/css/typography.css";

/* Optional CSS utils that can be commented out */
import "@ionic/react/css/padding.css";
import "@ionic/react/css/float-elements.css";
import "@ionic/react/css/text-alignment.css";
import "@ionic/react/css/text-transformation.css";
import "@ionic/react/css/flex-utils.css";
import "@ionic/react/css/display.css";

/* Theme variables */
import "./theme/variables.css";

const App: React.FC = () => (
	<IonApp>
		<IonReactRouter>
			<IonTabs>
				<IonRouterOutlet>
					<Route exact path="/home">
						<Tab1 />
					</Route>
					<Route exact path="/addproduct">
						<Tab2 />
					</Route>
					<Route path="/info">
						<Tab3 />
					</Route>
					<Route exact path="/">
						<Redirect to="/tab1" />
					</Route>
				</IonRouterOutlet>
				<IonTabBar slot="bottom">
					<IonTabButton tab="tab1" href="/home">
						<IonIcon icon={homeOutline} />
					</IonTabButton>
					<IonTabButton tab="tab2" href="/addproduct">
						<IonIcon icon={addCircleOutline} />
					</IonTabButton>
					<IonTabButton tab="tab3" href="/info">
						<IonIcon icon={informationCircleOutline} />
					</IonTabButton>
				</IonTabBar>
			</IonTabs>
		</IonReactRouter>
	</IonApp>
);

export default App;

Si ejecutamos nuestra aplicación obtendremos el siguiente resultado.
ionic serve



Para poder observar la comunicación en tiempo real debemos ejecutar la aplicación en 2 pestañas diferentes del navegador en una pestaña agreguemos un producto y en la otra pestaña veremos como automáticamente después de agregar un producto nos aparece una notificación que un nuevo producto se agregó.

 
puedes descargar el código desde este repositorio

si quieren donarme para una café lo pueden hacer aqui.

Hasta la próxima.

Saludos desde El Salvador...

Publicar un comentario

0 Comentarios