Upgrade React guides for react-scripts 5.0.0 (#19)
This commit is contained in:
parent
e3b7cf9a3d
commit
10be3e4e7f
|
@ -17,8 +17,140 @@ For this guide, we are using a single content topic: `/min-react-js-chat/1/chat/
|
||||||
Create a new React app:
|
Create a new React app:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
npx create-react-app min-react-js-chat
|
npx create-react-app relay-reactjs-chat
|
||||||
cd min-react-js-chat
|
cd relay-reactjs-chat
|
||||||
|
```
|
||||||
|
|
||||||
|
## `BigInt`
|
||||||
|
|
||||||
|
Some of js-waku's dependencies use [`BigInt`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt)
|
||||||
|
that is [only supported by modern browsers](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt#browser_compatibility).
|
||||||
|
|
||||||
|
To ensure that `react-scripts` properly transpile your webapp code, update the `package.json` file:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"browserslist": {
|
||||||
|
"production": [
|
||||||
|
">0.2%",
|
||||||
|
"not ie <= 99",
|
||||||
|
"not android <= 4.4.4",
|
||||||
|
"not dead",
|
||||||
|
"not op_mini all"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Setup polyfills
|
||||||
|
|
||||||
|
A number of Web3 dependencies need polyfills.
|
||||||
|
Said polyfills must be explicitly declared when using webpack 5.
|
||||||
|
|
||||||
|
The latest `react-scripts` version uses webpack 5.
|
||||||
|
|
||||||
|
We will describe below a method to configure polyfills when using `create-react-app`/`react-scripts` or webpack 5.
|
||||||
|
This may not be necessary if you do not use `react-scripts` or if you use webpack 4.
|
||||||
|
|
||||||
|
Start by installing the polyfill libraries:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
npm install assert buffer crypto-browserify stream-browserify
|
||||||
|
```
|
||||||
|
|
||||||
|
### Webpack 5
|
||||||
|
|
||||||
|
If you directly use webpack 5,
|
||||||
|
then you can inspire yourself from this [webpack.config.js](https://github.com/status-im/wakuconnect-vote-poll-sdk/blob/main/examples/mainnet-poll/webpack.config.js).
|
||||||
|
|
||||||
|
### cra-webpack-rewired
|
||||||
|
|
||||||
|
An alternative is to let `react-scripts` control the webpack 5 config and only override some elements using `cra-webpack-rewired`.
|
||||||
|
|
||||||
|
Install `cra-webpack-rewired`:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
npm install -D cra-webpack-rewired
|
||||||
|
```
|
||||||
|
|
||||||
|
Create a `config/webpack.extend.js` file at the root of your app:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const webpack = require('webpack');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
dev: (config) => {
|
||||||
|
// Override webpack 5 config from react-scripts to load polyfills
|
||||||
|
if (!config.resolve) config.resolve = {};
|
||||||
|
if (!config.resolve.fallback) config.resolve.fallback = {};
|
||||||
|
Object.assign(config.resolve.fallback, {
|
||||||
|
buffer: require.resolve('buffer'),
|
||||||
|
crypto: require.resolve('crypto-browserify'),
|
||||||
|
stream: require.resolve('stream-browserify'),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!config.plugins) config.plugins = [];
|
||||||
|
config.plugins.push(
|
||||||
|
new webpack.DefinePlugin({
|
||||||
|
'process.env.ENV': JSON.stringify('dev'),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
config.plugins.push(
|
||||||
|
new webpack.ProvidePlugin({
|
||||||
|
process: 'process/browser.js',
|
||||||
|
Buffer: ['buffer', 'Buffer'],
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!config.ignoreWarnings) config.ignoreWarnings = [];
|
||||||
|
config.ignoreWarnings.push(/Failed to parse source map/);
|
||||||
|
|
||||||
|
return config;
|
||||||
|
},
|
||||||
|
prod: (config) => {
|
||||||
|
// Override webpack 5 config from react-scripts to load polyfills
|
||||||
|
if (!config.resolve) config.resolve = {};
|
||||||
|
if (!config.resolve.fallback) config.resolve.fallback = {};
|
||||||
|
Object.assign(config.resolve.fallback, {
|
||||||
|
buffer: require.resolve('buffer'),
|
||||||
|
crypto: require.resolve('crypto-browserify'),
|
||||||
|
stream: require.resolve('stream-browserify'),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!config.plugins) config.plugins = [];
|
||||||
|
config.plugins.push(
|
||||||
|
new webpack.DefinePlugin({
|
||||||
|
'process.env.ENV': JSON.stringify('prod'),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
config.plugins.push(
|
||||||
|
new webpack.ProvidePlugin({
|
||||||
|
process: 'process/browser.js',
|
||||||
|
Buffer: ['buffer', 'Buffer'],
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!config.ignoreWarnings) config.ignoreWarnings = [];
|
||||||
|
config.ignoreWarnings.push(/Failed to parse source map/);
|
||||||
|
|
||||||
|
return config;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Use `cra-webpack-rewired` in the `package.json`, instead of `react-scripts`:
|
||||||
|
|
||||||
|
```
|
||||||
|
"scripts": {
|
||||||
|
- "start": "react-scripts start",
|
||||||
|
- "build": "react-scripts build",
|
||||||
|
- "test": "react-scripts test",
|
||||||
|
- "eject": "react-scripts eject"
|
||||||
|
+ "start": "cra-webpack-rewired start",
|
||||||
|
+ "build": "cra-webpack-rewired build",
|
||||||
|
+ "test": "cra-webpack-rewired test",
|
||||||
|
+ "eject": "cra-webpack-rewired eject"
|
||||||
|
},
|
||||||
```
|
```
|
||||||
|
|
||||||
Then, install [js-waku](https://npmjs.com/package/js-waku):
|
Then, install [js-waku](https://npmjs.com/package/js-waku):
|
||||||
|
@ -33,15 +165,6 @@ Start the dev server and open the dApp in your browser:
|
||||||
npm run start
|
npm run start
|
||||||
```
|
```
|
||||||
|
|
||||||
Note: We have noticed some [issues](https://github.com/status-im/js-waku/issues/165) 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
|
# Create Waku Instance
|
||||||
|
|
||||||
In order to interact with the Waku network, you first need a Waku instance.
|
In order to interact with the Waku network, you first need a Waku instance.
|
||||||
|
@ -76,12 +199,13 @@ function App() {
|
||||||
return (
|
return (
|
||||||
<div className='App'>
|
<div className='App'>
|
||||||
<header className='App-header'>
|
<header className='App-header'>
|
||||||
// Display the status on the web page
|
<p>Waku node's status: {wakuStatus}</p>
|
||||||
<p>{wakuStatus}</p>
|
|
||||||
</header>
|
</header>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default App;
|
||||||
```
|
```
|
||||||
|
|
||||||
# Wait to be connected
|
# Wait to be connected
|
||||||
|
@ -136,9 +260,9 @@ Create a function that takes the Waku instance and a message to send:
|
||||||
```js
|
```js
|
||||||
import { WakuMessage } from 'js-waku';
|
import { WakuMessage } from 'js-waku';
|
||||||
|
|
||||||
const ContentTopic = `/min-react-js-chat/1/chat/proto`;
|
const ContentTopic = `/relay-reactjs-chat/1/chat/proto`;
|
||||||
|
|
||||||
function sendMessage(message, timestamp, waku) {
|
function sendMessage(message, waku, timestamp) {
|
||||||
const time = timestamp.getTime();
|
const time = timestamp.getTime();
|
||||||
|
|
||||||
// Encode to protobuf
|
// Encode to protobuf
|
||||||
|
@ -184,7 +308,7 @@ function App() {
|
||||||
<div className="App">
|
<div className="App">
|
||||||
<header className="App-header">
|
<header className="App-header">
|
||||||
<p>{wakuStatus}</p>
|
<p>{wakuStatus}</p>
|
||||||
<button onClick={sendMessageOnClick} disabled={wakuStatus !== 'Ready'}> // Grey the button is Waku is not yet ready.
|
<button onClick={sendMessageOnClick} disabled={wakuStatus !== 'Ready'}>
|
||||||
Send Message
|
Send Message
|
||||||
</button>
|
</button>
|
||||||
</header>
|
</header>
|
||||||
|
@ -302,4 +426,4 @@ function App() {
|
||||||
And Voilà! You should now be able to send and receive messages.
|
And Voilà! You should now be able to send and receive messages.
|
||||||
Try out by opening the app from different browsers.
|
Try out by opening the app from different browsers.
|
||||||
|
|
||||||
You can see the complete code in the [Minimal ReactJS Chat App](https://github.com/status-im/js-waku/tree/main/examples/min-react-js-chat).
|
You can see the complete code in the [Relay ReactJS Chat Example App](https://github.com/status-im/js-waku/tree/main/examples/relay-reactjs-chat).
|
||||||
|
|
|
@ -33,8 +33,140 @@ Check out the [how to choose a content topic guide](/docs/guides/01_choose_conte
|
||||||
Create a new React app:
|
Create a new React app:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
npx create-react-app my-app
|
npx create-react-app store-reactjs-chat
|
||||||
cd my-app
|
cd store-reactjs-chat
|
||||||
|
```
|
||||||
|
|
||||||
|
## `BigInt`
|
||||||
|
|
||||||
|
Some of js-waku's dependencies use [`BigInt`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt)
|
||||||
|
that is [only supported by modern browsers](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt#browser_compatibility).
|
||||||
|
|
||||||
|
To ensure that `react-scripts` properly transpile your webapp code, update the `package.json` file:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"browserslist": {
|
||||||
|
"production": [
|
||||||
|
">0.2%",
|
||||||
|
"not ie <= 99",
|
||||||
|
"not android <= 4.4.4",
|
||||||
|
"not dead",
|
||||||
|
"not op_mini all"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Setup polyfills
|
||||||
|
|
||||||
|
A number of Web3 dependencies need polyfills.
|
||||||
|
Said polyfills must be explicitly declared when using webpack 5.
|
||||||
|
|
||||||
|
The latest `react-scripts` version uses webpack 5.
|
||||||
|
|
||||||
|
We will describe below a method to configure polyfills when using `create-react-app`/`react-scripts` or webpack 5.
|
||||||
|
This may not be necessary if you do not use `react-scripts` or if you use webpack 4.
|
||||||
|
|
||||||
|
Start by installing the polyfill libraries:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
npm install assert buffer crypto-browserify stream-browserify
|
||||||
|
```
|
||||||
|
|
||||||
|
### Webpack 5
|
||||||
|
|
||||||
|
If you directly use webpack 5,
|
||||||
|
then you can inspire yourself from this [webpack.config.js](https://github.com/status-im/wakuconnect-vote-poll-sdk/blob/main/examples/mainnet-poll/webpack.config.js).
|
||||||
|
|
||||||
|
### cra-webpack-rewired
|
||||||
|
|
||||||
|
An alternative is to let `react-scripts` control the webpack 5 config and only override some elements using `cra-webpack-rewired`.
|
||||||
|
|
||||||
|
Install `cra-webpack-rewired`:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
npm install -D cra-webpack-rewired
|
||||||
|
```
|
||||||
|
|
||||||
|
Create a `config/webpack.extend.js` file at the root of your app:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const webpack = require('webpack');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
dev: (config) => {
|
||||||
|
// Override webpack 5 config from react-scripts to load polyfills
|
||||||
|
if (!config.resolve) config.resolve = {};
|
||||||
|
if (!config.resolve.fallback) config.resolve.fallback = {};
|
||||||
|
Object.assign(config.resolve.fallback, {
|
||||||
|
buffer: require.resolve('buffer'),
|
||||||
|
crypto: require.resolve('crypto-browserify'),
|
||||||
|
stream: require.resolve('stream-browserify'),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!config.plugins) config.plugins = [];
|
||||||
|
config.plugins.push(
|
||||||
|
new webpack.DefinePlugin({
|
||||||
|
'process.env.ENV': JSON.stringify('dev'),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
config.plugins.push(
|
||||||
|
new webpack.ProvidePlugin({
|
||||||
|
process: 'process/browser.js',
|
||||||
|
Buffer: ['buffer', 'Buffer'],
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!config.ignoreWarnings) config.ignoreWarnings = [];
|
||||||
|
config.ignoreWarnings.push(/Failed to parse source map/);
|
||||||
|
|
||||||
|
return config;
|
||||||
|
},
|
||||||
|
prod: (config) => {
|
||||||
|
// Override webpack 5 config from react-scripts to load polyfills
|
||||||
|
if (!config.resolve) config.resolve = {};
|
||||||
|
if (!config.resolve.fallback) config.resolve.fallback = {};
|
||||||
|
Object.assign(config.resolve.fallback, {
|
||||||
|
buffer: require.resolve('buffer'),
|
||||||
|
crypto: require.resolve('crypto-browserify'),
|
||||||
|
stream: require.resolve('stream-browserify'),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!config.plugins) config.plugins = [];
|
||||||
|
config.plugins.push(
|
||||||
|
new webpack.DefinePlugin({
|
||||||
|
'process.env.ENV': JSON.stringify('prod'),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
config.plugins.push(
|
||||||
|
new webpack.ProvidePlugin({
|
||||||
|
process: 'process/browser.js',
|
||||||
|
Buffer: ['buffer', 'Buffer'],
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!config.ignoreWarnings) config.ignoreWarnings = [];
|
||||||
|
config.ignoreWarnings.push(/Failed to parse source map/);
|
||||||
|
|
||||||
|
return config;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Use `cra-webpack-rewired` in the `package.json`, instead of `react-scripts`:
|
||||||
|
|
||||||
|
```
|
||||||
|
"scripts": {
|
||||||
|
- "start": "react-scripts start",
|
||||||
|
- "build": "react-scripts build",
|
||||||
|
- "test": "react-scripts test",
|
||||||
|
- "eject": "react-scripts eject"
|
||||||
|
+ "start": "cra-webpack-rewired start",
|
||||||
|
+ "build": "cra-webpack-rewired build",
|
||||||
|
+ "test": "cra-webpack-rewired test",
|
||||||
|
+ "eject": "cra-webpack-rewired eject"
|
||||||
|
},
|
||||||
```
|
```
|
||||||
|
|
||||||
Then, install [js-waku](https://npmjs.com/package/js-waku):
|
Then, install [js-waku](https://npmjs.com/package/js-waku):
|
||||||
|
@ -49,7 +181,8 @@ Start the dev server and open the dApp in your browser:
|
||||||
npm run start
|
npm run start
|
||||||
```
|
```
|
||||||
|
|
||||||
Note: We have noticed some [issues](https://github.com/status-im/js-waku/issues/165) with React bundling due to `npm` pulling an old version of babel.
|
{{< hint info >}}
|
||||||
|
We have noticed some [issues](https://github.com/status-im/js-waku/issues/165) 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)
|
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:
|
character not being valid, try cleaning up and re-installing your dependencies:
|
||||||
|
|
||||||
|
@ -57,6 +190,7 @@ character not being valid, try cleaning up and re-installing your dependencies:
|
||||||
rm -rf node_modules package-lock.json
|
rm -rf node_modules package-lock.json
|
||||||
npm install
|
npm install
|
||||||
```
|
```
|
||||||
|
{{< /hint >}}
|
||||||
|
|
||||||
# Create Waku Instance
|
# Create Waku Instance
|
||||||
|
|
||||||
|
@ -90,12 +224,13 @@ function App() {
|
||||||
return (
|
return (
|
||||||
<div className='App'>
|
<div className='App'>
|
||||||
<header className='App-header'>
|
<header className='App-header'>
|
||||||
// Display the status on the web page
|
|
||||||
<p>{wakuStatus}</p>
|
<p>{wakuStatus}</p>
|
||||||
</header>
|
</header>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default App;
|
||||||
```
|
```
|
||||||
|
|
||||||
# Wait to be connected
|
# Wait to be connected
|
||||||
|
@ -217,40 +352,43 @@ const processMessages = (retrievedMessages) => {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
Finally, pass `processMessage` in `WakuStore.queryHistory` as the `callback` value:
|
Pass `processMessage` in `WakuStore.queryHistory` as the `callback` value:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
waku.store
|
waku.store
|
||||||
.queryHistory([ContentTopic], { callback: processMessages });
|
.queryHistory([ContentTopic], { callback: processMessages });
|
||||||
```
|
```
|
||||||
|
|
||||||
All together, you should now have:
|
Finally, create a `Messages` component to render the messages:
|
||||||
|
|
||||||
```js
|
```tsx
|
||||||
const ContentTopic = '/toy-chat/2/huilong/proto';
|
function Messages(props) {
|
||||||
|
return props.messages.map(({ text, timestamp, nick }) => {
|
||||||
|
return (
|
||||||
|
<li>
|
||||||
|
({formatDate(timestamp)}) {nick}: {text}
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatDate(timestamp) {
|
||||||
|
return timestamp.toLocaleString([], {
|
||||||
|
month: 'short',
|
||||||
|
day: 'numeric',
|
||||||
|
hour: 'numeric',
|
||||||
|
minute: '2-digit',
|
||||||
|
second: '2-digit',
|
||||||
|
hour12: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Use `Messages` in the `App` function:
|
||||||
|
|
||||||
|
```tsx
|
||||||
function App() {
|
function App() {
|
||||||
// [..]
|
// [..]
|
||||||
// Store messages in the state
|
|
||||||
const [messages, setMessages] = React.useState([]);
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
if (wakuStatus !== 'Connected') return;
|
|
||||||
|
|
||||||
const processMessages = (retrievedMessages) => {
|
|
||||||
const messages = retrievedMessages.map(decodeMessage).filter(Boolean);
|
|
||||||
|
|
||||||
setMessages((currentMessages) => {
|
|
||||||
return currentMessages.concat(messages.reverse());
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
waku.store
|
|
||||||
.queryHistory([ContentTopic], { callback: processMessages })
|
|
||||||
.catch((e) => {
|
|
||||||
console.log('Failed to retrieve messages', e);
|
|
||||||
});
|
|
||||||
}, [waku, wakuStatus]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='App'>
|
<div className='App'>
|
||||||
|
@ -264,13 +402,138 @@ function App() {
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
All together, you should now have:
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { Waku } from 'js-waku';
|
||||||
|
import * as React from 'react';
|
||||||
|
import protons from 'protons';
|
||||||
|
|
||||||
|
const ContentTopic = '/toy-chat/2/huilong/proto';
|
||||||
|
|
||||||
|
const proto = protons(`
|
||||||
|
message ChatMessage {
|
||||||
|
uint64 timestamp = 1;
|
||||||
|
string nick = 2;
|
||||||
|
bytes text = 3;
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
|
||||||
|
function App() {
|
||||||
|
const [waku, setWaku] = React.useState(undefined);
|
||||||
|
const [wakuStatus, setWakuStatus] = React.useState('None');
|
||||||
|
const [messages, setMessages] = React.useState([]);
|
||||||
|
|
||||||
|
// Start Waku
|
||||||
|
React.useEffect(() => {
|
||||||
|
// If Waku status not None, it means we are already starting Waku
|
||||||
|
if (wakuStatus !== 'None') return;
|
||||||
|
|
||||||
|
setWakuStatus('Starting');
|
||||||
|
|
||||||
|
// Create Waku
|
||||||
|
Waku.create({ bootstrap: true }).then((waku) => {
|
||||||
|
// Once done, put it in the state
|
||||||
|
setWaku(waku);
|
||||||
|
// And update the status
|
||||||
|
setWakuStatus('Connecting');
|
||||||
|
});
|
||||||
|
}, [waku, wakuStatus]);
|
||||||
|
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (!waku) return;
|
||||||
|
|
||||||
|
if (wakuStatus === 'Connected') return;
|
||||||
|
|
||||||
|
waku.waitForConnectedPeer().then(() => {
|
||||||
|
setWakuStatus('Connected');
|
||||||
|
});
|
||||||
|
}, [waku, wakuStatus]);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (wakuStatus !== 'Connected') return;
|
||||||
|
|
||||||
|
const processMessages = (retrievedMessages) => {
|
||||||
|
const messages = retrievedMessages.map(decodeMessage).filter(Boolean);
|
||||||
|
|
||||||
|
setMessages((currentMessages) => {
|
||||||
|
return currentMessages.concat(messages.reverse());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
waku.store
|
||||||
|
.queryHistory([ContentTopic], { callback: processMessages })
|
||||||
|
.catch((e) => {
|
||||||
|
console.log('Failed to retrieve messages', e);
|
||||||
|
});
|
||||||
|
}, [waku, wakuStatus]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='App'>
|
||||||
|
<header className='App-header'>
|
||||||
|
<h2>{wakuStatus}</h2>
|
||||||
|
<h3>Messages</h3>
|
||||||
|
<ul>
|
||||||
|
<Messages messages={messages} />
|
||||||
|
</ul>
|
||||||
|
</header>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default App;
|
||||||
|
|
||||||
|
function decodeMessage(wakuMessage) {
|
||||||
|
if (!wakuMessage.payload) return;
|
||||||
|
|
||||||
|
const { timestamp, nick, text } = proto.ChatMessage.decode(
|
||||||
|
wakuMessage.payload
|
||||||
|
);
|
||||||
|
|
||||||
|
// All fields in protobuf are optional so be sure to check
|
||||||
|
if (!timestamp || !text || !nick) return;
|
||||||
|
|
||||||
|
const time = new Date();
|
||||||
|
time.setTime(timestamp);
|
||||||
|
|
||||||
|
const utf8Text = Buffer.from(text).toString('utf-8');
|
||||||
|
|
||||||
|
return { text: utf8Text, timestamp: time, nick };
|
||||||
|
}
|
||||||
|
|
||||||
|
function Messages(props) {
|
||||||
|
return props.messages.map(({ text, timestamp, nick }) => {
|
||||||
|
return (
|
||||||
|
<li>
|
||||||
|
({formatDate(timestamp)}) {nick}: {text}
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatDate(timestamp) {
|
||||||
|
return timestamp.toLocaleString([], {
|
||||||
|
month: 'short',
|
||||||
|
day: 'numeric',
|
||||||
|
hour: 'numeric',
|
||||||
|
minute: '2-digit',
|
||||||
|
second: '2-digit',
|
||||||
|
hour12: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Note that `WakuStore.queryHistory` select an available store node for you.
|
Note that `WakuStore.queryHistory` select an available store node for you.
|
||||||
However, it can only select a connected node, which is why the bootstrapping is necessary.
|
However, it can only select a connected node, which is why the bootstrapping is necessary.
|
||||||
It will throw an error if no store node is available.
|
It will throw an error if no store node is available.
|
||||||
|
|
||||||
|
If no message are returned,
|
||||||
|
then you can use https://status-im.github.io/js-waku/ to send some messages on the
|
||||||
|
toy chat topic and refresh your app.
|
||||||
|
|
||||||
## Filter messages by send time
|
## Filter messages by send time
|
||||||
|
|
||||||
By default, Waku Store nodes store messages for 30 days.
|
By default, Waku Store nodes store messages for 30 days.
|
||||||
|
|
Loading…
Reference in New Issue