Para facilitar las comunicaciones del socket en React, usarás el socket de la biblioteca de-facto.io-client. Utilice el comandodnpm install -S socket.io-client para instalarlo.
Hay múltiples formas de añadir soporte para WebSocket a una aplicación de React. Cada método tiene sus pros y sus contras. Esta guía repasará algunos de los patrones comunes, pero sólo explorará en detalle el patrón que estamos implementando.
Integración a nivel de componentes
En este método, podrías asumir la parte de los WebSockets como un uso separado. Iniciaría una conexión de sockets en el inicio de AppComponent como un singleton y utilizaría la instancia de sockets para escuchar los mensajes de sockets que son relevantes para el componente en particular. A continuación se presenta un ejemplo de implementación:
123456789101112131415161718import{ socket }de$0027socketUtil.js$0027;import{ useDispatch }de$0027react-redux$0027;functionChatRoomComponent(){const dispatch =useDispatch();useEffect(()= >socket. on($0027event://get-message$0027,payload= >{/// actualizar mensajesuseDispatch({ type:UPDATE_CHAT_LOG}, payload)}); socket.on($0027event:// user-joined$0027,payload====;{/// manejar un nuevo usuario que se une a la sala});});// otras implementaciones}
javascript
Como puedes ver arriba, esto segrega completamente las implementaciones de Redux y WebSocket y da un patrón de «plug-and-play». Este método es útil si estás implementando WebSockets a unos pocos componentes de una aplicación existente, por ejemplo, si tienes una aplicación de blog y quieres proporcionar notificaciones push en tiempo real. En ese caso, sólo necesita WebSockets para el componente de notificación y este patrón sería una forma limpia de implementar. Pero si la aplicación tiene muchos sockets, este método se convertiría eventualmente en una carga para desarrollar y mantener. El uso del socket funciona independientemente y no funciona bien con los ciclos de vida de React. Además, los múltiples enlaces de eventos en cada componente eventualmente ralentizarían toda la aplicación.
Integración del Middleware Redux
Otro enfoque popular es introducir los WebSockets como un middleware para la tienda. Esto armoniza perfectamente la naturaleza asíncrona del WebSocket con el patrón de flujo de datos unidireccional de Redux. En la implementación, una conexión WebSocket se iniciaría en el inicio del middleware, y los eventos subsecuentes del socket se delegarían internamente a las acciones de Redux. Por ejemplo, cuando la carga útil event://get-message llega al cliente, el middleware enviará la acción UPDATE_CHAT_LOG internamente. Los reductores entonces actualizarían la tienda con el siguiente conjunto de mensajes. Si bien este es un enfoque interesante, no será discutido en profundidad en esta guía. Para su referencia, este artículo proporciona excelentes indicaciones sobre la implementación. Este método es ideal si un WebSocket es una parte integral de la aplicación y se espera que se acople estrechamente con Redux.
Integración del Contexto de Reacción
El método final es el uso del Contexto de Reacción para facilitar la comunicación en el WebSocket. En esta guía se repasará la implementación y luego se discutirá por qué se prefiere esto al resto. El Contexto de Reacción se introdujo como una forma de gestionar el estado de la aplicación sin pasar por los árboles padre-hijo. Con la reciente introducción de Hooks, el uso de Context se volvió trivial.
Primero, crearás una clase de Contexto para WebSockets que inicialice la conexión del socket.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647// WebSocket.jsimportReact,{ createContext }from$0027react$0027import io from$0027socket. io-client$0027;import{WS_BASE}from$0027./config$0027;import{ useDispatch }from$0027react-redux$0027;import{ updateChatLog }from$0027. /acciones$0027;constWebSocketContext=createContext(null)export{WebSocketContext}exportdefault({ children })={ {let socket;let ws;const dispatch =useDispatch();constsendMessage=(roomId, message)={const payload ={ roomId: roomId, data: message } socket. emit("event://enviar-mensaje",JSON.stringify(payload));dispatch(updateChatLog(payload));}if(!socket){ socket = io.connect(WS_BASE) socket.on("event://get-message",(msg)=>{const payload =JSON. parse(msg);dispatch(updateChatLog(payload));}) ws ={ socket: socket, sendMessage }}return(<WebSocketContext.Provider value={ws};{children}</WebSocketContext.Provider;}
javascript
Obsérvese que se introdujeron dos funciones adicionales:
- Envío de mensajes de socorroLa función de emisión está encapsulada dentro de funciones con nombres definitivos. Por ejemplo, sendMessage emitiría esencialmente un mensaje de socorro como el siguiente.
12evento: eventos://enviar-mensaje-cargar: <;contenido del mensaje
- Recepción de mensajes de socorroTodos los mensajes de socorro que se reciben se asignan a las respectivas acciones Redux. Dado que el contexto del WebSocket se utilizará dentro del proveedor de Redux, tendrá acceso al método de envío de Redux.
A primera vista, esta aplicación parecería exagerada y demasiado parecida al primer método antes mencionado. Pero unas pocas diferencias clave añaden un gran valor a largo plazo.
- La iniciación del WebSocket funciona como parte del ciclo de Reacción. En caso de fallo del socket, se puede manejar fácilmente o proporcionar retroalimentación al usuario. Esto se puede manejar de forma centralizada.
- Para un evento determinado, sólo habrá un evento vinculante. Ya que cada evento se corresponde con una acción Redux, no hay ataduras repetitivas por componentes individuales. Cuando la aplicación se escala, esto evita muchos arañazos en la cabeza.
- Todas las acciones de los enchufes están envueltas en funciones que permiten un control firme sobre la estructura de la carga útil y validaciones sobre los parámetros.
- Todos los códigos relacionados con los enchufes están disponibles centralmente en un solo lugar. Aunque esto está en la lista de ventajas, en ciertas condiciones (por ejemplo: microfrentes) esto podría ser un problema. Pero en la mayoría de los casos, esto sería una ventaja.
Con estas características, la integración basada en el contexto se adapta bien a la escalabilidad, así como al mantenimiento de la base de código. Ahora que se ha creado el WebSocketContext, se puede explorar cómo usarlo funcionalmente.
1234567891011// actions.jsexportconstSEND_MESSAGE_REQUEST="SEND_MESSAGE_REQUEST "exportconstUPDATE_CHAT_LOG="UPDATE_CHAT_LOG "exportfunctionupdateChatLog(update){return{ type:UPDATE_CHAT_LOG, update }}
javascript
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465// App.jsimportWebSocketProvider,{WebSocketContext}from$0027./WebSocket$0027;// ... functionApp(){return(<Provider store={store};<WebSocketProvider,// div className="App"<HomeComponent/{N-]/div /Provider>)}}funciónChatRoom(){const[usernameInput, setUsernameInput]=useState("");const[msgInput, setMsgInput]=useState("");const room =useSelector(state=> state. room);const nombredeusuario =useSelector(state=> state.nombredeusuario);const chats =useSelector(state=> state.chatLog);const despacho =useDispatch();const ws =useContext(WebSocketContext);functionenterRooom(){dispatch(setUsername(usernameInput));}constsendMessage=()=mph;{ ws.sendMessage(room. id,{ username: nombre de usuario, mensaje: msgInput });}return(<div>h3;{room.name}({room.id})</h3;};{!username &&<div className="user"<input type="text" placeholder="Enter username" value={usernameInput} onChange={(e)=>setUsernameInput(e.target. valor)}/{Nbotón onClick={enterRooom}{entrarSala</botón}{nombredeusuario &&};div className="sala"};div className="historia" style={{{ancho: "400px", borde: "1px sólido #ccc", altura: "100px", textoAlineado: "izquierda", relleno: "10px", desbordamiento: "scroll"}};{chats. map((c, i)=;(<div key={i};i};{c.username}:</i>{c.message}</div;))}</div>div className="control"<input type="text" value={msgInput} onChange={(e)=; setMsgInput(e.
javascriptComo se ha mostrado anteriormente, el uso de la integración basada en el contexto es limpio. Se puede acceder al contexto del WebSocket desde cualquier lugar de la aplicación utilizando el useContext Hook, y todas las funcionalidades incluidas estarán disponibles. Además, una aplicación del mundo real también necesitaría manejar las instancias de desconexión y reconexión del socket, y manejar la salida del cliente. Estas instancias pueden ser fácilmente añadidas al WebSocketContext, dejando el resto de la aplicación limpia.