# Receive and Send Messages Using Waku Relay With ReactJS It is easy to use DappConnect with ReactJS. In this guide, we will demonstrate how your ReactJS dApp can use Waku Relay to send and receive messages. Before starting, you need to choose a _Content Topic_ for your dApp. Check out the [how to choose a content topic guide](choose-content-topic.md) to learn more about content topics. For this guide, we are using a single content topic: `/min-js-web-chat/1/chat/proto`. # Setup Create a new react app: ```shell npx create-react-app min-js-web-chat cd min-js-web-chat ``` Then, install [js-waku](https://npmjs.com/package/js-waku): ```shell npm install js-waku ``` Start the dev server and open the dApp in your browser: ```shell npm run start ``` Note: We have noticed some issues with React bundling due to `npm` pulling an old version of babel. If you are getting an error about the [optional chaining (?.)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining) character not being valid, try cleaning up and re-installing your dependencies: ```shell rm -rf node_modules package-lock.json npm install ``` # Create Waku Instance In order to interact with the Waku network, you first need a Waku instance. Go to `App.js` and modify the `App` function: ```js import { Waku } from 'js-waku'; import * as React from 'react'; function App() { const [waku, setWaku] = React.useState(undefined); const [wakuStatus, setWakuStatus] = React.useState('None'); // Start Waku React.useEffect(() => { // If Waku is already assigned, the job is done if (!!waku) return; // If Waku status not None, it means we are already starting Waku if (wakuStatus !== 'None') return; setWakuStatus('Starting'); // Create Waku Waku.create().then((waku) => { // Once done, put it in the state setWaku(waku); // And update the status setWakuStatus('Started'); }); }, [waku, wakuStatus]); return (
// Display the status on the web page

{wakuStatus}

); } ``` # Connect to Other Peers The Waku instance needs to connect to other peers to communicate with the network. First, create `bootstrapWaku` to connect to the Status fleet: ```js import { getStatusFleetNodes } from 'js-waku'; async function bootstrapWaku(waku) { // Retrieve node addresses from https://fleets.status.im/ const nodes = await getStatusFleetNodes(); // Connect to the nodes await Promise.all(nodes.map((addr) => waku.dial(addr))); } ``` Then, bootstrap after Waku is created in the previous `useEffect` block: ```js React.useEffect(() => { if (!!waku) return; if (wakuStatus !== 'None') return; setWakuStatus('Starting'); Waku.create().then((waku) => { setWaku(waku); setWakuStatus('Connecting'); bootstrapWaku(waku).then(() => { setWakuStatus('Ready'); }); }); }, [waku, wakuStatus]); ``` DappConnect will provide more discovery and bootstrap methods over time, or you can make your own. # Define Message Format To define the Protobuf message format, use [protons](https://www.npmjs.com/package/protons) ```shell npm install protons ``` Define `SimpleChatMessage` with two fields: `timestamp` and `text`. ```js import protons from 'protons'; const proto = protons(` message SimpleChatMessage { uint64 timestamp = 1; string text = 2; } `); ``` # Send Messages Create a function that takes the Waku instance and a message to send: ```js import { WakuMessage } from 'js-waku'; const ContentTopic = `/min-js-web-chat/1/chat/proto`; async function sendMessage(message, timestamp, waku) { const time = timestamp.getTime(); // Encode to protobuf const payload = proto.SimpleChatMessage.encode({ timestamp: time, text: message, }); // Wrap in a Waku Message const wakuMessage = await WakuMessage.fromBytes(payload, ContentTopic); // Send over Waku Relay await waku.relay.send(wakuMessage); } ``` Then, add a button to the `App` function: ```js function App() { const [waku, setWaku] = React.useState(undefined); const [wakuStatus, setWakuStatus] = React.useState('None'); // Using a counter just for the messages to be different const [sendCounter, setSendCounter] = React.useState(0); React.useEffect(() => { // ... creates Waku }, [waku, wakuStatus]); const sendMessageOnClick = () => { // Check Waku is started and connected first. if (wakuStatus !== 'Ready') return; sendMessage(`Here is message #${sendCounter}`, waku, new Date()).then(() => console.log('Message sent') ); // For demonstration purposes. setSendCounter(sendCounter + 1); }; return (

{wakuStatus}

); } ``` # Receive Messages To process incoming messages, you need to register an observer on Waku Relay. First, you need to define the observer function. You will need to remove the observer when the component unmount. Hence, you need the reference to the function to remain the same. For that, use `React.useCallback`: ```js const processIncomingMessage = React.useCallback((wakuMessage) => { // Empty message? if (!wakuMessage.payload) return; // Decode the protobuf payload const { timestamp, text } = proto.SimpleChatMessage.decode( wakuMessage.payload ); const time = new Date(); time.setTime(timestamp); // For now, just log new messages on the console console.log(`message received at ${time.toString()}: ${text}`); }, []); ``` Then, add this observer to Waku Relay. Do not forget to delete the observer is the component is being unmounted: ```js React.useEffect(() => { if (!waku) return; // Pass the content topic to only process messages related to your dApp waku.relay.addObserver(processIncomingMessage, [ContentTopic]); // `cleanUp` is called when the component is unmounted, see ReactJS doc. return function cleanUp() { waku.relay.deleteObserver(processIncomingMessage, [ContentTopic]); }; }, [waku, wakuStatus, processIncomingMessage]); ``` # Display Messages The Waku work is now done. Your dApp is able to send and receive messages using Waku. For the sake of completeness, let's display received messages on the page. First, add incoming messages to the state of the `App` component: ```js function App() { //... const [messages, setMessages] = React.useState([]); const processIncomingMessage = React.useCallback((wakuMessage) => { if (!wakuMessage.payload) return; const { text, timestamp } = proto.SimpleChatMessage.decode( wakuMessage.payload ); const time = new Date(); time.setTime(timestamp); const message = { text, timestamp: time }; setMessages((currMessages) => { return [message].concat(currMessages); }); }, []); // ... } ``` Then, render the messages: ```js function App() { // ... return (

{wakuStatus}

); } ``` And VoilĂ ! You should now be able to send and receive messages. Try out by opening the app from different browsers. You can see the complete code in the [Minimal JS Web Chat App](/examples/min-js-web-chat).