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);
});
}
Related
I need to create a custom fetch composable from VueUse using createFetch() and I want to check if a request returns 401 status, I'd like the route to be redirected to the login route.
export const useApiFetch = createFetch({
baseUrl: import.meta.env.VITE_API_BASE_URL,
options: {
beforeFetch({ options }) {
const { user } = useSessionStore()
if (user)
options.headers.Authorization = `Basic ${user.user_id}:${user.password}`
return { options }
},
onFetchError(response) {
const route = useRoute()
const router = useRouter()
if (route.name !== 'login' && response.status === 401)
return router.push('/login')
}
}
})
But everytime it hits the error, useRoute and useRouter are undefined, and yes.. I have checked that it runs in setup
<script setup>
const submit = async () => {
const { error, data } = await useApiFetch('/login').post(form)
}
</script>
Did I miss something or is there a better way to do this? thanks
Vue composables are primarily expected to be called in setup block. Other usages depend on their implementation and needs to be confirmed. The main restriction is that a composable is linked to specific component instance, in this case useRouter uses provide/inject to get router instance through component hierarchy; this often can be be deduced without checking the actual implementation.
It's possible to directly import router instance instead of using useRouter but this may result in module circular dependencies and this may not be work for other composables.
createFetch wasn't designed for this usage and needs to be wrapped with custom composable that guarantees that other composables will be called in time:
let useApiFetchFn;
const useApiFetch = (...args) => {
if (!useApiFetchFn) {
const sessionStore = useSessionStore()
const route = useRoute()
const router = useRouter()
useApiFetchFn = createFetch(...)
}
return useApiFetchFn(...args);
}
Whether it's correct to cache the result to useApiFetchFn depends on the implementation, in this case it's acceptable. At this point it may be more straightforward to use useFetch directly and compose the options similarly to how createFetch does that, most of its code is dedicated to TS support and variadic arguments that may not be needed in this case.
I am trying to use local variable inside the included code but getting an error.
app.js:
import RequireDir from "require-dir";
import { Server, Socket } from "socket.io";
...
client.on("connection", (socket) => {
const id = socket.id;
RequireDir("./data", { recurse: true, noCache: true });
}
data/main.js:
console.log(id);
It will show this error on Runtime:
ReferenceError: id is not defined
There is any solution?
You cannot access variables that are initialized inside a function outside of that function.
The question is what you are trying to do with that socket ID. This socket ID is unique for each session, and you should not expose that to global variables.
The best approach would be to write a function that takes that ID and handles it.
data/main.js:
export const handleSocket = (socket) => {
console.log(socket.id);
// ... rest of your code
};
app.js:
import RequireDir from "require-dir";
import { Server, Socket } from "socket.io";
import { handleSocket } from "data/main.js"; // import the function
...
client.on("connection", (socket) => {
// pass socket to your handler
handleSocket(socket);
RequireDir("./data", { recurse: true, noCache: true });
}
You might want to read about javascript closures to understand scoping of variables.
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've configured a simple Vue project using the vue-cli tool:
vue init webpack my-project
Now I want to send some information through a web socket before the page gets rendered. Since I don't want to tie this logic to the Vue component, I have a different js file (named ws.js and based in this):
import Vue from 'vue'
const websocket = new WebSocket('ws://localhost:1234')
const emitter = new Vue({
name: 'emitter',
methods: {
send (message) {
websocket.send(JSON.stringify(message))
}
}
})
export default emitter
When the page loads, I use the emitter object to send some info:
<template>
<div class="hello">
TEST
</div>
</template>
<script>
import emitter from '../ws/ws'
export default {
name: 'HelloWorld',
beforeMount () {
emitter.send('Hello')
}
}
</script>
And I get this error in Firefox console:
[Vue warn]: Error in beforeMount hook: "InvalidStateError: An attempt
was made to use an object that is not, or is no longer, usable"
found in
---> at src/components/HelloWorld.vue
at src/App.vue
What am I doing wrong? Should I attach to a different event listener rather than beforeMount()? If I comment out the WebSocket related lines, the error disappears:
import Vue from 'vue'
// const websocket = new WebSocket('ws://localhost:1234')
const emitter = new Vue({
name: 'emitter',
methods: {
send (message) {
// websocket.send(message)
}
}
})
export default emitter
I need to write for the socket before it's in ready state before sending any message, so based in this answer I have changed ws.js to this:
import Vue from 'vue'
const websocket = new WebSocket('ws://localhost:1234')
// Make the function wait until the connection is made...
function waitForSocketConnection (socket, callback) {
setTimeout(
function () {
if (socket.readyState === 1) {
console.log('Connection is made')
if (callback != null) {
callback()
}
} else {
console.log('wait for connection...')
waitForSocketConnection(socket, callback)
}
}, 5) // wait 5 milisecond for the connection...
}
function sendWaiting (msg) {
waitForSocketConnection(websocket, () => {
console.log('Sending ' + msg)
websocket.send(msg)
console.log('Sent ' + msg)
})
}
const emitter = new Vue({
name: 'emitter',
methods: {
send (message) {
sendWaiting(message)
}
}
})
export default emitter
Now, before sending any message the application checks if the WebSocket is ready and sends it, otherwise it rechecks each 5 milliseconds until it is.
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;