I heard that Socket.io not worked properly in React Native, so I decided to use plain WebSocket instead.
I'm using node.js for implemeting WebSocket server, and it wasn't hard. With browsers, all of I tried worked, but with React native, none of success.
These are what I tried for implementing websocket server:
express-ws
ws
express-ws was just not worked without any error message. Just it saids failed to connect something.
So I changed the module to ws, and this module should be required both client and server, so I did. Server was worked, but when in the app with android on AVD, it saids:
Requiring unknown module "url".If you are sure the module is there,
try restarting the packager or running "npm install".
So I removed node_modules directory entirely and reinstall them, but same error shown up again.
I'm using node v6.2.2, and react-native-cli 1.0.0, react-native 0.33.0.
This is the server code with ws module(same as ws module readme):
var WebSocketServer = require('ws').Server;
var wss = new WebSocketServer({ port: 3000 });
wss.on('connection', (socket) => {
socket.on('message', (msg) => {
console.log('Received: ' + msg);
});
socket.send('something');
});
This is client:
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View
} from 'react-native';
const WebSocket = require('ws');
class wschat extends Component {
constructor() {
super();
}
componentDidMount() {
var socket = new WebSocket("ws://localhost:3000");
socket.on('open', () => {
socket.send('something');
});
socket.on('message', (data, flags) => {
console.log(data);
console.log(flags);
});
}
...
To avoid naming conflict, I was used WebSock instead WebSocket when requiring ws module, but it wasn't problem.
Is there a something that I missed? React Native doc has not much explanations, and it is hard to find working examples. Thanks for reading, and any advice will very appreciate it.
The latest react native supports websocket, so we don't have to depend on 3rd party websocket client library.
The following example is based on react native 0.45, and the project is generated by create-react-native-app.
import React, {Component} from 'react';
import {Text, View} from 'react-native';
export default class App extends React.Component {
constructor() {
super();
this.state = {
echo: ''
};
}
componentDidMount() {
var socket = new WebSocket('wss://echo.websocket.org/');
socket.onopen = () => socket.send(new Date().toGMTString());
socket.onmessage = ({data}) => {
console.log(data);
this.setState({echo: data});
setTimeout(() => {
socket.send(new Date().toGMTString());
}, 3000);
}
}
render() {
return (
<View>
<Text>websocket echo: {this.state.echo}</Text>
</View>
);
}
}
Install this package npm install websocket on your react native folder. The link to the relevant Github repo is this
import React, { useEffect } from 'react';
import { w3cwebsocket as W3CWebSocket } from "websocket";
import { Text} from 'react-native';
var client = new W3CWebSocket('ws://localhost:8080/', 'echo-protocol');
function App() {
client.onopen = function() {
console.log('WebSocket Client Connected');
function sendNumber() {
if (client.readyState === client.OPEN) {
var number = Math.round(Math.random() * 0xFFFFFF);
client.send(number.toString());
setTimeout(sendNumber, 1000);
}
}
sendNumber();
};
client.onclose = function() {
console.log('echo-protocol Client Closed');
};
client.onmessage = function(e) {
if (typeof e.data === 'string') {
console.log("Received: '" + e.data + "'");
}
};
return (
<Text>Practical Intro To WebSockets.</Text>
);
}
export default App;
Related
Can anyone provide successful implementation of Stomp using the latest version of ActiveMQ 5.x using the React N? How to connect and publish to the queue?
I have below questions:
I have to retrieve the data from consumer and do some add some boolean value and send it to publish.
How can I keep the connection alive because continuously I will get message in queues.
How can I implement this in React.js in simple manner (any plugins)
I tried with JavaScript, and it works as expected.
consumer.js
const Stomp = require("stomp-client");
const stompClient = new Stomp("127.0.0.1",61613);
stompClient.connect( function(sessionId){
console.log("consumer connected");
stompClient.subscribe("/queue/<name>",function(body){
console.log(body);
});
});
producer.js
const Stomp = require("stomp-client");
const stompClient = new Stomp("127.0.0.1",61613);
stompClient.connect( function(sessionId){
console.log("producer connected");
stompClient.publish("/queue/<name>",function(body){
console.log(body);
console.log(typeof(body));
//JSON.stringify(body);
});
stompClient.disconnect();
});
This is what I tried in React.JS (which failed): here i can able to connect and after that if i call subscribe with que name it is not giving any response
import './App.css';
import React,{useEffect} from 'react';
import { Client, Message } from '#stomp/stompjs';
function App() {
const clientdata = new Client();
useEffect(() => {
clientdata.configure({
brokerURL: 'ws://localhost:61614/stomp',
onConnect: (frame) => {
console.log('onConnect');
console.log(frame);
clientdata.subscribe('/queue/<quename>',info => {
console.log(info);
})
console.log(subscription);
},
// Helps during debugging, remove in production
debug: (str) => {
// console.log(new Date(), str);
}
});
client.activate();
}, []);
return (
<div >
</div>
);
}
export default App;
When i tried the above code I am getting only connected log and I'm not able to subscribe any thing and not seeing anything.
I'd like to have socket.io available across the whole Svelte app. I don't know what I am doing wrong...
store.js
export const socket = writable();
This works
App.svelte
import { io } from "socket.io-client";
import { socket } from "./stores.js";
$socket = io();
$socket.on("orders", (orders) => {
console.log(orders);
});
This doesn't
App.svelte
import { io } from "socket.io-client";
import { socket } from "./stores.js";
$socket = io();
Component.svelte
import { socket } from "./stores.js";
$socket.on("orders", (orders) => {
console.log(orders);
});
The code shown works as long as the execution order is guaranteed to be correct, i.e. the code in App running before the code in Component.
If it is not, you need to add additional logic to handle the store not being set. (You also probably should clean up these on event handlers via onDestroy as well.)
E.g. you can use a reactive statement to check whether the store was set, if it is initialized with null:
$: if ($socket != null) {
$socket.on("orders", (orders) => {
console.log(orders);
});
}
the problem
I created a Shopify node.js app using the Shopify CLI and I want to display a simple bar under the header using a script tag. I used the script tag API to add a script tag
"script_tags": [
{
"id": 174240039086,
"src": "https://xxxxx.ngrok.io/script_tag",
}
]
And I also added a <div id="script-app"></div> into the theme, under the header.
Here is my script_tag.js file, located in /pages/script_tag.js
import ReactDOM from 'react-dom';
class TestScriptTag extends React.Component {
constructor() {
super();
}
render() {
return (
<div>
<p>this is a bar</p>
</div>
);
}
}
ReactDOM.render(<TestScriptTag />, document.getElementById('script-app'));
export default TestScriptTag;
Lastly, here is my server.js (most of it is what came with the CLI):
import "#babel/polyfill";
import dotenv from "dotenv";
import "isomorphic-fetch";
import createShopifyAuth, { verifyRequest } from "#shopify/koa-shopify-auth";
import Shopify, { ApiVersion } from "#shopify/shopify-api";
import Koa from "koa";
import next from "next";
import Router from "koa-router";
import { flushSync } from "react-dom";
const fs = require('fs');
dotenv.config();
const port = parseInt(process.env.PORT, 10) || 8083;
const dev = process.env.NODE_ENV !== "production";
const app = next({
dev,
});
const handle = app.getRequestHandler();
Shopify.Context.initialize({
API_KEY: process.env.SHOPIFY_API_KEY,
API_SECRET_KEY: process.env.SHOPIFY_API_SECRET,
SCOPES: process.env.SCOPES.split(","),
HOST_NAME: process.env.HOST.replace(/https:\/\//, ""),
API_VERSION: ApiVersion.October20,
IS_EMBEDDED_APP: false,
// This should be replaced with your preferred storage strategy
SESSION_STORAGE: new Shopify.Session.MemorySessionStorage(),
});
// Storing the currently active shops in memory will force them to re-login when your server restarts. You should
// persist this object in your app.
const ACTIVE_SHOPIFY_SHOPS = {};
app.prepare().then(async () => {
const server = new Koa();
const router = new Router();
server.keys = [Shopify.Context.API_SECRET_KEY];
server.use(
createShopifyAuth({
async afterAuth(ctx) {
console.log("here")
// Access token and shop available in ctx.state.shopify
const { shop, accessToken, scope } = ctx.state.shopify;
const host = ctx.query.host;
ACTIVE_SHOPIFY_SHOPS[shop] = scope;
const response = await Shopify.Webhooks.Registry.register({
shop,
accessToken,
path: "/webhooks",
topic: "APP_UNINSTALLED",
webhookHandler: async (topic, shop, body) =>
delete ACTIVE_SHOPIFY_SHOPS[shop],
});
if (!response.success) {
console.log(
`Failed to register APP_UNINSTALLED webhook: ${response.result}`
);
}
// Redirect to app with shop parameter upon auth
ctx.redirect(`/?shop=${shop}&host=${host}`);
},
})
);
const handleRequest = async (ctx) => {
await handle(ctx.req, ctx.res);
ctx.respond = false;
ctx.res.statusCode = 200;
};
router.get("/", async (ctx) => {
const shop = ctx.query.shop;
// This shop hasn't been seen yet, go through OAuth to create a session
if (ACTIVE_SHOPIFY_SHOPS[shop] === undefined) {
ctx.redirect(`/auth?shop=${shop}`);
} else {
await handleRequest(ctx);
}
});
router.get("/script_tag", (ctx) => {
handleRequest(ctx);
});
router.get("(/_next/static/.*)", handleRequest); // Static content is clear
router.get("/_next/webpack-hmr", handleRequest); // Webpack content is clear
router.get("(.*)", verifyRequest(), handleRequest); // Everything else must have sessions
server.use(router.allowedMethods());
server.use(router.routes());
server.listen(port, () => {
console.log(`> Ready on http://localhost:${port}`);
});
});
I am getting the error: document not defined.
What I've tried
I thought this is due to server side rendering, so I thought I could get around it by doing this:
if (typeof window !== "undefined") {
ReactDOM.render(<TestScriptTag />, document.getElementById('script-app'));
}
But still nothing renders and I get this when I inspect the shop page.
I've also tried changing the routing to this:
router.get("/script_tag", (ctx) => {
ctx.type = "module";
ctx.body = fs.createReadStream('./pages/script_tag.js')
});
But then I get an error about the import statement in script_tag.js - SyntaxError: Unexpected identifier '{'. import call expects exactly one argument.
I'm not sure what the proper way is to serve the javascript file I want to inject into the header. I feel like I'm missing something stupid. Please help!!
I tried to google some guides or tutorials and didn't found any. Is there any way to integrate into my react-native app a Parse SDK same as to android and iOS way? Because I tried to integrate Parse-SDK-JS and it didn't work now my app, crashing with error Error: Unable to resolve module crypto from node_modules\parse\node_modules\crypto-js\core.js: crypto could not be found within the project.'
my code:
parse.ts:
// In a React Native application
import Parse, { Error } from 'parse';
// On React Native >= 0.50 and Parse >= 1.11.0, set the Async
import { AsyncStorage } from 'react-native';
export const initParse = () => {
Parse.setAsyncStorage(AsyncStorage);
Parse.initialize('xxxxxxxxxxxxxxxxxxxxxxxxxxx'); //APP_ID
Parse.serverURL = 'https://xxx.herokuapp.com/parse'; //HEROKU URI SERVER
};
export const testCreate = () => {
const GameScore = Parse.Object.extend('GameScore');
const gameScore = new GameScore();
gameScore.set('score', 1337);
gameScore.set('playerName', 'Sean Plott');
gameScore.set('cheatMode', false);
gameScore.save().then(
(gameScore: any) => {
// Execute any logic that should take place after the object is saved.
alert('New object created with objectId: ' + gameScore.id);
},
(error: Error) => {
// Execute any logic that should take place if the save fails.
// error is a Parse.Error with an error code and message.
alert('Failed to create new object, with error code: ' + error.message);
},
);
};
index.js:
/**
* #format
*/
import {
AppRegistry
} from 'react-native';
import {
initParse
} from './src/library/parse/parse';
import App from './App';
import {
name as appName
} from './app.json';
initParse();
AppRegistry.registerComponent(appName, () => App);
You need to import Parse from parse/react-native.js. It should be something like this:
import Parse, { Error } from 'parse/react-native.js';
I am trying to implement Web Workers in my React app to share a single WebSockets connection over multiple tabs. I use the worker-loader dependency for loading in Web Workers.
Unfortunately i can't even get a simple dedicated web worker to work.
App.jsx:
import React, { Component } from 'react';
// eslint-disable-next-line
import myWorker from 'worker-loader!./worker.js';
class App extends Component {
constructor(props) {
super();
this.state = {};
}
componentWillMount() {
if(window.SharedWorker) {
console.log(myWorker);
myWorker.port.postMessage('Hello worker');
myWorker.port.onmessage = function(e) {
console.log('Message received from worker');
console.log(e.data);
}
}
worker.js:
onconnect = function(e) {
var port = e.ports[0];
port.onmessage = function(e) {
var workerResult = 'Result: ' + (e.data[0] * e.data[1]);
port.postMessage(workerResult);
}
}
When loading the page the following webpack error appears:
I can't use the config style usage of worker-loader because that requires some changes in the webpack config. This config can't be edited because of create-react-app. I could if i eject create-react-app, but that does have some disadvantages.
Why doesn't it work? Somebody any ideas?
Thanks in advance,
Mike
As #KevBot indicated i had to create a new instance of the Worker:
// eslint-disable-next-line
import Worker from 'worker-loader!./worker.js';
let myWorker = new Worker();