victorhas / mqtt-react-hooks Goto Github PK
View Code? Open in Web Editor NEWReactJS library for Pub/Sub communication with an MQTT broker using Hooks
License: MIT License
ReactJS library for Pub/Sub communication with an MQTT broker using Hooks
License: MIT License
mqtt-react-hooks declares the dependency for mqtt as "^4.2.8", which at the time of writing will install mqtt 4.3.5 on a fresh installation. This results in published messages not being deleted from the outgoing mqtt.Store with qos 1, even if PUBACK is received. Forcing the dependency to mqtt 4.2.8 resolves the problem.
There are no types being exported for typescript users.
I'm trying to do the following in React with the mqtt-react-hooks:
This is an example of the function that I'm using (note the comments for additional info)
export default function MqttConn(){
const url_works = "ws://mymqttserver:myport/mqtt"; // This works
const url_doesntwork = variable_from_json_config_file; // This doesnt work
// I need to call a function to get each users login info, so "myOptions" is initially blank
const [myOptions, setState]=useState({
username:"",
password:"",
clientId:"",
keepAlive: 60,
clean: true
});
useEffect(()=>{
My_Function_Checks_Server('someFunction', (error,response)=>{
if(e){console.log(e)}
//---
setState({
username: response.mqttUser,
password: response.mqttPass,
clientId: response.mqttTopic
});
//---
});
}, []);
return (
<Connector brokerUrl={url_works} options={myOptions}>
<Status/>
<div>
Test area for "setState" {/* This proves that all variables are fetched and correct*/}
<ul>
<li> Username: {myOptions.username} </li>
<li> Password: {myOptions.password} </li>
<li> ClientId: {myOptions.clientId} </li>
</ul>
</div>
</Connector>
)
}
My observations are:
Without these features this plugin cannot scale, so can you please guide me on how to use the variables for this hook, whether through a json config or a server side function call?
Thank you
Originally posted by @coderantongmail in #13 (comment)
1- If I have several components that are independent of each other, I add a subscription to a topic in the right component with the appropriate logic, but the component that was subscribed to another topic automatically receives all messages from all subscriptions. Is this normal behavior or was it intended a little differently?
For example as in the screenshots below:
As a result, I had to do an additional check for the topic I needed, otherwise I received a bunch of unnecessary messages that should have been only in the diagnostic component.
2- After the second component has been destroyed, the subscription is saved all the same. It is necessary to make it possible to unsubscribe from the topic when the component is destroyed. More precisely, add the ability to unsubscribe in the library
3 - If I disable broker status not changed to reconnecting, this is bug. And if broker run again, mqtt is reconnect, but status in connectionStatus not change if broker is down.
Hello VictorHAS! First of all, thank you very much for this repo, so incredibly useful.
tl;dr I'm getting this error when I call useSubscription().
./src/components/App.js
Attempted import error: 'useSubscription' is not exported from 'mqtt-react-hooks'.
I just got this app spun up and started messing with your library so everything in question is happening within App.js, which I've included below in its entirety.
As you can see I got useSubscribeState() to work, but it returns an entire array of all the MQTT messages. So impressive but too much! All I want is the latest message in [messages]. I suspect that useSubscription() will meet my needs but I'm running into that import error, which I thought may be useful to bring up here. Any and all advice/feedback is extremely welcomed - as you can tell I'm pretty new to React. Thank you very much!
import React from 'react';
import './App.css';
import { useMqttState, useSubscribeState } from 'mqtt-react-hooks';
import { useSubscription } from 'mqtt-react-hooks';
const App = () => {
const { mqtt } = useMqttState();
const { messages } = useSubscribeState();
const sendMessage = (message) => {
console.log('Sent over MQTT: ' + message);
return mqtt.publish('@', message);
}
// const test = useSubscription('leapCurrentSpeed');
// console.log(test);
const updateSpeed = (messages) => {
if (messages !== undefined && messages.length !== 0) {
console.log(messages);
// Sketchy way of getting to the last message in [messages]
const messagesLength = messages.length;
const message = JSON.parse(messages[messagesLength - 1].message);
if (message.hasOwnProperty('currentSpeed')) {
const { currentSpeed } = message;
return currentSpeed;
}
}
else {
const currentSpeed = 100;
// console.log('in else statement');
return currentSpeed;
}
}
return (
<div className="App">
<button onClick={() => sendMessage('test message')}>
Send MQTT message
</button>
<div className="speedReading">
{updateSpeed(messages)}
</div>
</div>
)
}
export default App;
I'm working on a project that uses react 17, which means I'm having to be pinned to the most recent commit before the dependency update. Would it be possible to support older react versions?
Test files are ignored by git, shouldn't they be visible? We can't run any tests.
So I have time to work with that lib again, but I need to know what I can improve. It seems that there is an incompatible version between react and mqttjs. I will be analyzing in the next few days and trying to correct these errors. Maybe, there is a version 3.0.0 with the code all refactored
I'm unable to connect to the Mosquitto test broker via the URL listed in the README (mqtt://test.mosquitto.org:1884
). I have also tried:
mqtt://test.mosquitto.org:8883
- Failmqtt://test.mosquitto.org:1883/
- Failws://test.mosquitto.org:8080/
- Failwss://test.mosquitto.org:8081/
- ConnectsSo far only the last URL connects. I suspect those using the MQTT protocol fail because MQTT.js can't open the TCP socket by default.
EDIT: The error I see is WebSocket connection to 'ws://test.mosquitto.org:1884/' failed
I'm working with a device that uses binary messages and publishing isn't a problem using Uint8Array
, but after subscribing to a topic I never got any msgs
. I'm seeing the messages in websocket communication in the browser's developer tools, so I suspect it is a result of the toString()
.
I just wanted to make an issue to note the limitation in case it is something others run into. I appreciate the effort put into the library and respect that this may not get fixed.
Hey guys, just tried out mqtt-react-hooks with VITEJS and seems not compatible since it call node functions and would need polyfiller for VITEJS, but adding a node polyfiller does not helps, can something be done to make this library work with Vitejs?
Thanks!
When I stop my (mosquitto) broker the status is not updated and the browser logs shows:
"Websocket connection to 'ws://:port/" failed: ws.js:108
I would like to control the connection using a state value. Can you please add a Boolean property "connect" to the Connector which will indicate if to perform a connection or not.
This will support:
`
const [connect, setConnet) = useState(false);
return (
<Connector connect={connect}
{children components here that will optionally require mqtt}
</Connector
)
`
I'm using mqtt-react-hooks with Webpack 5 and React 18 (manually added polyfill dependencies to work) to connect via MQTT over WebSocket to the Aedes broker. On the other side, there's an IoT device that every time publishes 5 test messages on a received command.
I have a problem that the built-in useSubscription hook, which returns the received, doesn't catch all published messages that it should. For comparison, Paho MQTT and the MQTTX app catch all 5 messages, while this library catches only 3 or 4, very rarely all 5. All messages are binary because we're using Google Protocol buffers, but I guess that shouldn't be a problem. Because of that, I'm using the parser method parserMethod={msg => msg}
on the Connector.
The source code to listen to the messages is as follows:
const { message } = useSubscription(deviceToCloudTopic);
useEffect(() => {
if (message) {
onMessageArrivedHandler(message);
console.log(message);
}
}, [message]);
Is this a known issue or am I doing something wrong?
Hello! I am using
"mqtt-react-hooks": "^2.0.3",
"next": "11.1.2",
"react": "17.0.2",
"react-dom": "17.0.2"
In my setup, the Connector
connects to ws://test.mosquitto.org:8080
. I tried various other servers to verify this problem persists.
Even without a useSubscription
hook, the module attempts to connect every few milliseconds.
Even though I get 101 switching protocols.
Interestingly, I also only get Status: undefined
This is the code:
import { Connector, useMqttState } from 'mqtt-react-hooks'
const Home: NextPage = () => {
const { connectionStatus } = useMqttState()
return (
<div>
<Connector brokerUrl="ws://test.mosquitto.org:8080">
{ `Status: ${connectionStatus}` }
</Connector>
</div>
)
}
export default Home
I added a codesandbox where I can also observe the problem: https://codesandbox.io/s/headless-water-8hfcv
Hi, im using a MQTT broker with authentication but cant figure out where to parse the credentials in this library.
Am I blind or is it not implemented yet? :)
thanks in advance
In my code I do the following:
import { useSubscription } from 'mqtt-react-hooks';
const Freezer = (props) => {
const { message } = useSubscription("camper/sensors/freezer")
useEffect(() => {
console.log(message)
}, [message])
return (
<>
<div>
<AcUnit style={{ fill: "darkblue" }} />
<span>Freezer {message?.topic} °C</span>
</div>
</>
);
}
export default Freezer;
However, the message variable remains undefined.
In MQTT Explorer I see that the topic exists and that is contains messages.
Also In the developer tools network tab I see messages being received.
Does someone have an idea what could be the problem?
Is it possible to change MQTT Broker on the fly, ?
I have setup Local MQTT which is accessible via Local network,
So when ever phone is connected to wifi I want to use Local MQTT, and when phone connected to mobile internet it should connect to another MQTT over internet.
Got this error after installing the package to a TypeScript React project
Failed to compile.
./node_modules/mqtt-react-hooks/dist/index.es.js
Attempted import error: 'uuid' does not contain a default export (imported as 'i').
The version is "mqtt-react-hooks": "^1.2.0"
Right now, every newly created example will fail to run in the browser, with the above error. This seems to be related to an import referenced in this issue, but I just can't seem to locate it in the code of "
mqtt-react-hooks". Also mentioned in this issue, so many MQTT libs have this problem right now.
To reproduce the issue:
Can reproduce every time. Some suggest to solve this by downgrading "react-script", but that's not a real fix and causes other problems.
package.json contents:
{
"name": "mqtt-demo-react",
"version": "0.1.0",
"private": true,
"dependencies": {
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"mqtt-react-hooks": "^3.0.0-alpha.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"url": "^0.11.0",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
hi
i need to subscribe 2 topics in at a time.
so i pass 2 topic in 'useSubscription' with array but i just get message for first topic
for example like this:
const { message } = useSubscription(['topic/1', 'topic/2']);
is this correct?
Is it possible to receive message of 2 topics at the same time?
Originally posted by @mehrdad24 in #13 (comment)
I was thinking that we can have an object or map for the state where we can take a topic as key in obj. This would be more configuration for the developer. We are having many topics that are only giving updates about something and old information is not needed. You can think of live views
which is getting an update when a new user is joining and leaving but we just need to have current live views information for this.
I have a react application with multiple components which are shown in a tab like structure like a browser with multiple tabs. Using mui buttons I'm able to display the corresponding tab however the MQTT connection closed with the 1005 errorcode. After trying lots of things I run out ideas so solve this.
Does someone have an idea what could be the problem?
WebSocket connection to 'wss://192.168.1.125:8084/' failed
The message array (msgs) in useSubscription(topic) always returns all messages detected and are never cleared. This is effectively a memory leak since all messages are stored in that said array, imagine a IOT device pushing millions of messages to a topic and this array contains them all.
I feel that the message array should only contain the retained messages of the topic, also i feel like useSubscription should return a subscription function we could use to subscribe to new messages. Example:
const { subscribe, unsubscribe } = useSubscription("test");
useEffect(() => {
const id = subscribe(message => {
console.log(message);
});
return function cleanup() {
unsubscribe(id);
}
}, []);
OR
const { subscribe } = useSubscription("test");
useEffect(() => {
const unsubscribe = subscribe(message => {
console.log(message);
});
return function cleanup() {
unsubscribe();
}
}, []);
Hello, thanks again for writing this module. I am using nextJS which may be causing part of the behavior issues, or be unrelated. I open a connector in the app.js and I can connect fine and see connection status in another page using:
const { connectionStatus } = useMqttState();
however this throws the error:
const { message } = useSubscription('queuesList');
code in skillpage:
import React, { useEffect, useState } from 'react';
import { useMqttState, useSubscription } from 'mqtt-react-hooks';
export default function SkillPage() {
const { connectionStatus } = useMqttState();
const { message } = useSubscription('queuesList');
return (
The i.off line of code is in your index.es.js file. Also I noticed if I import client, then do client.subscribe - that works fine still.
You have subscribe as a dependency here: https://github.com/VictorHAS/mqtt-react-hooks/blob/V3/lib/useSubscription.tsx#L45
Every time I publish from a device that hook runs and disconnects based on the clean up logic.
How can we use authentication with MQTT username and password?
Use the provided example I tried this
export default function MqttConn(){
const url = "some url:port"
return (
<Connector brokerUrl={url}>
<Status/>
</Connector>
)
}
The status shows as "Connecting" which is expected, but I need to provide username and password to connect. Please help.
Thanks
Hello,
I'm using docker container running a mosquitto broker. Works fine with mqtt.js library. However, when I try to use the Connector provider it disconnects/reconnects on a loop. Here's the output:
mosquitto | 1668119874: New client connected from ::ffff:172.23.0.1:57598 as mqttjs_41060487 (p2, c1, k0).
mosquitto | 1668119874: No will message specified.
mosquitto | 1668119874: Sending CONNACK to mqttjs_41060487 (0, 2)
mosquitto | 1668119874: Client mqttjs_41060487 closed its connection.
I'm using vite and added the following line to the vite config resolve: { alias: { mqtt: "mqtt/dist/mqtt.js" }
I got it to work with test.mosquitto.org but then ran into the client undefined issue
I'd love to get this working locally. Here' is my mosquitto.conf
persistence false
listener 1883
allow_anonymous true
listener 8083
protocol websockets
Here is a similar issue with a Node Red client:
Thanks!
I got a error from use Subscription example ( TypeError: Cannot read properties of undefined (reading 'topic') )
`import React from 'react';
import { useSubscription } from 'mqtt-react-hooks';
export default function Status() {
/* Message structure:
return (
<>
<div style={{ display: 'flex', flexDirection: 'column' }}>
{topic:${message.topic} - message: ${message.message}
}
</>
);
}`
How can I fix it
If I make a very simple component that displays data from a subscription, I have found that it resubscribes every time it receives a new message. This is inefficient, and causes extra latency. My guess is that because the Mqtt client is passed through the context, message receipt changes the client, which then causes the consumers of the mqtt context to rerender. I am looking into this right now.
Hello everyone,
I am stuck using this package, which by the way seems to be nice and easy to use.
I am not able to connect to my broker using it.
The client state is null
The connectionStatus is stuck in "Connecting"
Moreover, in the network tab, 3 WS connections are initiated (101 Switching protocols) to my broker.
Why are 3 connection openned ? I logged how many renders occurs, and there is only one render.
I tried to reproduce this package using plain JS with the same code, and i can tell that the problem seemed to by related to the mountedRef ref, which happen to never be equal to true when entering in all listeners (on.connect , on.reconnect, on.error , etc. ) and so, never setting up the client or updating the connectionStatus.
Maybe my issue is related to the ref.
By the way, the broker is fully working, as I was previously using plain mqtt package without no issues. Tested also with public mqtt brokers, same results.
If someone has an idea ?
Thanks a lot !
i work with this package but found a problem of getting retained values
I've got a mosquitto broker set up on my machine that exposes a websocket on port 9001. Here's my configuration file contents:
allow_zero_length_clientid true
max_keepalive 65535
listener 1883
protocol mqtt
listener 1884 localhost
protocol mqtt
listener 9001
protocol websockets
require_certificate false
log_type all
websockets_log_level 1
allow_anonymous true
I have a very simple application that I believe others have used before to point out issues with connectionStatus.
import { IClientOptions } from 'mqtt';
import { Connector } from 'mqtt-react-hooks';
import Status from './Status';
const options: IClientOptions = {keepalive: 10, clientId: 'MyClient'};
const brokerUrl = "ws://localhost:9001";
function App() {
return (
<Connector brokerUrl={brokerUrl} options={options}>
<Status />
</Connector>
);
}
export default App;
import { useMqttState } from 'mqtt-react-hooks';
const Status = () => {
const {connectionStatus} = useMqttState();
return (
<div>{connectionStatus}</div>
);
}
export default Status;
If start with the mosquitto broker turned off, then turn it on, the page will correctly show the Reconnecting, Offline, and Connected connectionStatus
es (in that order). I also get a websocket console error while the mosquitto broker is offline.
However, once I CTRL+C to kill the mosquitto broker, the connectionStatus
continues to be shown as Connected, even though it is very obviously Offline.
In order to address this, I completely removed the mountedRef from Connector.tsx. I didn't understand what the point of this was. Likely because I'm so new to React. Once I removed all lines referencing mountedRef, I also added two more mqtt.on
lines inside the useCallback to handle disconnect
and close
.
My error is:
BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.
If you want to include a polyfill, you need to:
- add a fallback 'resolve.fallback: { "url": require.resolve("url/") }'
- install 'url'
If you don't want to include a polyfill, you can use an empty module like this:
resolve.fallback: { "url": false }
package.json :
{
"name": "mqtt-app",
"version": "0.1.0",
"private": true,
"dependencies": {
"@testing-library/jest-dom": "^5.16.1",
"@testing-library/react": "^12.1.2",
"@testing-library/user-event": "^13.5.0",
"mqtt-react-hooks": "^2.0.3",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-scripts": "5.0.0",
"web-vitals": "^2.1.3"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
Hi Team,
Am trying to connect over TCP Protocal. By default it's connecting By ws://
Where do i change that ?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.