Closed CrisRonda closed 3 weeks ago
Effectively the react native is unlikely to work - nats.ws is expecting a compliant ES w3c websocket environment.
Can you polyfill this with https://www.npmjs.com/package/react-native-url-polyfill?
you can try - I know that there are a few folks that have gotten older versions to work, but it is not clear if they got https://github.com/nats-io/nats.js to work or if it was https://github.com/nats-io/nats.ws.
@aricart is there a recommended approach for integrating NATS with React Native? Certainly this is a common ask, no?
It is not a very common ask, and it has been discussed that it should possibly be one of the supported clients.
@jfols Work with that polyfill So I'm going put all steps to run this package in react native
yarn add fastestsmallesttextencoderdecoder nats.ws node-libs-react-native react-native-url-polyfill text-encoding-polyfill
metro.config.js
like this:
module.exports = {
resolver: {
extraNodeModules: require('node-libs-react-native'),
},
...more config
};
index.js
/**
* Polyfills for nats.ws package
*/
import 'react-native-url-polyfill/auto';
import 'text-encoding-polyfill';
if (!Symbol.asyncIterator) { Symbol.asyncIterator = Symbol.for('Symbol.asyncIterator'); }
And that's all 🌟
Hi, anyone any tips on what the status is regarding working with nats on react-native?
Hi @pietgk I worked with nats and react native, so far I've not seen any problem. In order to use it: First follow the steps that I wrote Then you can create a hook to manage the subscriptions in the react native side, it could be some like this code:
import {connect, NatsConnection, consumerOpts} from 'nats.ws';
import {useCallback, useEffect, useRef} from 'react';
import {decode} from 'base-64';
const decodeMessageFromNatsServer = () => {
// YOUR LOGIC TO DECODE THE MESSAGE
}
const useNatsSubscription = ({
table,
onMessage,
}: {
table: string;
onMessage: (msg: object) => void;
}) => {
const nats = useRef<NatsConnection>();
const onSubscriptionMessage = useCallback(
async ({nameSubscription}: {nameSubscription: string}) => {
if (!nats.current) {
return;
}
const opts = consumerOpts({
name: 'MY_CHANNEL',
description: 'MY_CHANNEL_DESC',
});
opts.deliverNew();
opts.ackExplicit();
opts.manualAck();
nats.current
?.jetstream()
.pullSubscribe(nameSubscription, opts)
.then(async psub => {
psub?.pull({batch: 1});
for await (const m of psub) {
const payload = decodeMessageFromNatsServer(m);
if (payload) {
onMessage(payload);
}
m.ack();
psub.pull({batch: 1});
}
});
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[table],
);
const onSubscribe = useCallback(async () => {
try {
const nameSubscription = 'NAME_SUBSCRIPTION';
if (!nameSubscription) {
return;
}
// eslint-disable-next-line no-undef
const encoder = new TextEncoder();
const credentials = decode('NATS_USER_CRED_STRING');
const encodedCredentials = encoder.encode(credentials);
const nc = await connect({
debug: false,
servers: ['NATS_SERVER_ADDRESS'],
authenticator: encodedCredentials,
});
nats.current = nc;
await onSubscriptionMessage({nameSubscription});
} catch (error) {
console.log("ERROR: NATS Subscription", error);
}
}, []);
useEffect(() => {
onSubscribe();
return async () => {
await nats.current?.drain();
};
}, [onSubscribe]);
return {
onSubscribe,
};
};
export default useNatsSubscription;
// IN YOU COMPONENT
const sendedMessage = useRef(false);
const onRefresh = async () => {
// YOUT LOGIC
}
useNatsSubscription({
table: 'message',
onMessage: () => {
/* This code is part of a subscription to a NATS message queue. When a new message is received, it
checks if the `sendedMessage.current` flag is set to true. If it is, it means that the message
was sent by the current user and there is no need to refresh the conversation. If it is not
set, it calls the `onRefresh` function to refresh data with the new data/message. */
const refresh = async () => {
try {
if (sendedMessage.current) {
sendedMessage.current = false;
return;
}
await onRefresh(false);
} catch (error) {
} finally {
sendedMessage.current = false;
}
};
refresh().catch(error => console.log('on refresh', error));
},
});
@jfols Work with that polyfill So I'm going put all steps to run this package in react native
- Run in your terminal
yarn add fastestsmallesttextencoderdecoder nats.ws node-libs-react-native react-native-url-polyfill text-encoding-polyfill
- Update the
metro.config.js
like this:module.exports = { resolver: { extraNodeModules: require('node-libs-react-native'), }, ...more config };
- In your
index.js
/** * Polyfills for nats.ws package */ import 'react-native-url-polyfill/auto'; import 'text-encoding-polyfill'; if (!Symbol.asyncIterator) { Symbol.asyncIterator = Symbol.for('Symbol.asyncIterator'); }
And that's all 🌟
It works, thank you so much mate! I tried to develop my own TCP library, it worked, but was pretty unstable.
For other folks trying to fix this problem. You can follow steps above and start with this simple example to ensure that it works:
https://nats.io/blog/getting-started-nats-ws/#reactjs
Basically, once you are able to connect, you are good to go
I had this hook to connect to nats server. I am working with TS and React Native. I already tried this The error I see in the console is: [ERROR: URL.protocol is not implemented]
React Native info
nats.ws version: 1.14.0