diff --git a/examples/min-js-web-chat/src/App.js b/examples/min-js-web-chat/src/App.js
index 24fa5c04b4..dcb0382d19 100644
--- a/examples/min-js-web-chat/src/App.js
+++ b/examples/min-js-web-chat/src/App.js
@@ -15,9 +15,8 @@ message SimpleChatMessage {
function App() {
const [waku, setWaku] = React.useState(undefined);
const [wakuStatus, setWakuStatus] = React.useState('None');
- const [messages, setMessages] = React.useState([]);
- const [currentTime, setCurrentTime] = React.useState(new Date());
const [sendCounter, setSendCounter] = React.useState(0);
+ const [messages, setMessages] = React.useState([]);
React.useEffect(() => {
if (!!waku) return;
@@ -61,19 +60,10 @@ function App() {
};
}, [waku, wakuStatus, processIncomingMessage]);
- React.useEffect(() => {
- const timer = setInterval(() => {
- setCurrentTime(new Date());
- }, 1000);
- return () => {
- clearInterval(timer);
- };
- }, [currentTime]);
-
const sendMessageOnClick = () => {
if (wakuStatus !== 'Ready') return;
- sendMessage(`Here is message #${sendCounter}`, waku, currentTime).then(() =>
+ sendMessage(`Here is message #${sendCounter}`, waku, new Date()).then(() =>
console.log('Message sent')
);
diff --git a/guides/reactjs-relay.md b/guides/reactjs-relay.md
new file mode 100644
index 0000000000..4063260185
--- /dev/null
+++ b/guides/reactjs-relay.md
@@ -0,0 +1,309 @@
+# 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 unique 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 already started 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, waku, timestamp) {
+ 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 send messages 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 = () => {
+ if (wakuStatus !== 'Ready') return;
+
+ sendMessage(`Here is message #${sendCounter}`, waku, new Date()).then(() =>
+ console.log('Message sent')
+ );
+
+ 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 function that acts as observer.
+
+As you are passing the function to Waku Relay, it is best to use `React.useCallback` so that the reference to the function remains the same:
+
+```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 function as an 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, modify the `App()` function to store incoming messages:
+
+```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, add the messages to the rendering :
+
+```js
+function App() {
+ // ...
+
+ return (
+
+
+
{wakuStatus}
+
+
+ {messages.map((msg) => {
+ return (
+
+
+ {msg.timestamp.toString()}: {msg.text}
+
+
+ );
+ })}
+
+
+
+ );
+}
+```
+
+And VoilĂ ! You should now be able to send and receive messages from two different browsers.
+
+You can see the complete code in the [Minimal JS Web Chat App](/examples/min-js-web-chat).