why is Socket.io not working on client side? - javascript

I want to use socket.io-client on vanilla react without context.
This socket.on listener on third useEffect does not work if I don't re-render this page, where I have done setSocket(HomeScreen.jsx), the event no longer fires and I get Cannot read properties of null (reading 'emit'). So, if I want it to work, then I have to make this page re-render for the event to work after every successful event firing.
I am pretty sure this is a frontend mistake since I am console.logging all the socket.ids to emit successfully on the backend.
I would also like to know on how I can separate the third useEffect to a different component or have socket.io listeners on different component where I did not set the socket. Is it possible through passing components? If so, how?
I am new to socket.io-client and I want to use vanilla react without context. I thinik I am facing these issues due to not having proper structure on socket.io-client
This code for socket.io occurs after successful log in where I set the localStorage authToken and get to HomeScreen.jsx. Please help me out to better re-structure my socket.io code on the client side.
HomeScreen.jsx:
useEffect(() => {
if(localStorage.getItem('authToken') && !localStorage.getItem('showedLoginStatus')){
toast.success("Login successful!");
localStorage.setItem('showedLoginStatus', 'showed');
}
setSocket(io.connect(backendLink));
}, [])
useEffect(() => {
console.log(socket, localStorage.getItem('authToken'));
socket?.emit("newUser", localStorage.getItem('authToken'));
}, [socket])
useEffect(() => {
socket?.on("notifyFriendRequest", () => {
console.log('sent');
// readRequests();
})
return () => socket?.off("notifyFriendRequest");
}, [socket])

Related

Assigning onclick on button that is outside of current react app (php) gives unexpected behaviour

We are builidng react components for a php app, it doesn't really have much intergration but there's a php save button that is should listen for and save onclick. But there's a catch, for some reason most of functions i'm trying to use are just not getting ran. I'm working with react-form-hook and trying to run the onsubmit() with my function inside.
handleSubmit((data) => {
handleSaveOrderProducts(data, selectedProductsRef.current);
});
To assign this function to the button i have to listen for the button clicks with id, i tried different approaches but none seems to fix the problem. Ways to listen i tried:
Using https://www.npmjs.com/package/react-detect-click-outside#features lib
const productInformationContainerRef = useDetectClickOutside({
onTriggered(event) {
// #ts-ignore
if (event.target?.id === "save-order-button") {
console.log("save order button");
handleSubmit((data) => {
handleSaveOrderProducts(data, selectedProductsRef.current);
});
}
},
});
What i get in result? The callback itself runs, but the function (handlesubmit) is not. Even if i put a console.log in callback with data there's just nothing displayed.
Different approaches from this stackoverflow thread, mostly everything related to functional react Detect click outside React component .
If you had experience in something like this or have any theoretical knowledge please comment :)strong text

Authentication with Firebase and context API in react give me a warning. Is this the right approach?

I am trying to set up an authentication on my web application in React using firebase and Context API.
I am using Context API since as long as I understood I cannot save my jwt token in local storage in order to not be vulnerable to XSS attack and at the moment I do not want to use Redux.
in my App.js I have:
const {setUserInfo} = useContext(userInfoContext);
useEffect(() => {
auth.onAuthStateChanged(user => {
if (user) {
setUserInfo({jwtToken: user.za});
} else {
setUserInfo({jwtToken: null});
}
console.log(user);
});
}, [setUserInfo]);
The methos "auth.onAuthStateChanged" is triggered every time I logged in or I logged out using firebase.auth.
The compiler tell me that to eliminate the warning I should have "[setUserInfo]" instead of "[]". However, doing as he say, the method setUserInfo is executed twice. There is a better way to achieve the result without a warning?
Your problem is that you don't clean up your effect when it is recomputed. As soon as you add setUserInfo to the dependency array, the effect is executed whenever its value changes. This means that you could potentially register many auth.onAuthStateChanged if the value of setUserInfo changes.
auth.onAuthStateChanged returns an unsubscribe function. You can simply return this function inside your effect, which will make react execute the unsubscribe function whenever the hook is executed again and prevent you from having multiple active listeners. I suggest you read more about this topic here.

dynamically adding cards to the screen after sending a post request to database in Vuejs

I want to refresh my cardData array that gets its value by a get request from the database after I send a post request the the database. I have written this saveDraft() function that upon click adds values to cardData array but I need to refresh the page or click on it twice to see the changes. Is there a way to do it dynamically without refreshing the page?
saveDraft() {
Api.createComment({
// it's a post request
})
.then(res => {
if (response.status == 200) {
Api.getComments().then(res => {
// it's a get request to update the cardData
if (res.status === 200) {
this.cardData = res.data;
} else {
// catches error
}
});
} else {
// catches error
}
});
},
I can't exactly see how you've implemented the saveDraft() function but I'll work with what you gave!
To generally answer your question, I think it depends on what you mean by clicking on it twice or refreshing the page (i.e. 'clicking' meaning you've bound it to a user event such as #dblclick or #click?). But in Vue, you can handle dynamic events through the following:
1) Is this function in a child component? If yes, then consider using v-on directive to listen to user events (i.e. #dblclick, #click, #mouseover, etc.), emitting a custom event, or creating a watcher that 'updates' the data in a parent.
If this is confusing, you can check out the video by Vue Mastery on event handling that goes over the foundations of emitting events from the child component to the parent.
2) You can consider using Vuex as a state-manager. This can help with reactivity - of updating a component or piece of data being passed around through mutations and actions. Check out a general overview of Vuex and reactivity in Vue on Vue Mastery
If this still doesn't make sense, let me know here or update your question if needed :)

How to get electron autoUpdater instance inside Angular 9 app?

So I have an application that can run in electron, and it can auto update. The update server is up and can be used.
The problem is, my updater process runs in electron main process, not inside Angular app. I want the users to be able to check, and manually update the application themselves, which I think we need to implement main process instance inside my Angular app.
Here is how I call the updater inside main.js.
if (!require('electron-is-dev')) {
require('./updater');
} else {
console.log('App is running in dev environment')
}
And here is a slice of my updater.js
const { app, dialog, autoUpdater } = require('electron');
const server = 'http://my-release-server.com:5000';
const url = `${server}/update/${process.platform}/${app.getVersion()}`;
console.log(`[autoUpdater] init ${url}`);
autoUpdater.setFeedURL({ url });
setInterval(() => {
autoUpdater.checkForUpdates();
}, 30000)
autoUpdater.on('checking-for-update', () => {
console.log('[autoUpdater] Checking for updates');
});
// And other events handler.
My autoUpdater works like charm when I am using default setup, which runs the updater inside the main electron process, but I can not show or inform the user about the updating process.
So, is there any solution or right way to implement this thing? I learnt in some article to use electron remote which handled inter process communication, can I use that? Can I use angular service to handle these things?
Thank you.

Auth0 client is null in Vue SPA on page refresh

I have a Vue SPA based on one of Auth0's quickstart apps (https://github.com/auth0-samples/auth0-vue-samples). Everything works fine out of the box, but as soon as I try using the Auth0 client in my component code I run into problems. I followed the "Calling an API" tutorial (https://auth0.com/docs/quickstart/spa/vuejs/02-calling-an-api), which unhelpfully only shows how to call an API using a button. What I want to do is trigger an authenticated call to my API on initial page load so that I can ensure certain data exists in my own API (or create it if it does not). This seems like it should be pretty straightforward. I just throw this code in my created hook of my Vue component:
await this.$auth.getTokenSilently().then((authToken) => {
// reach out to my API using authToken
});
This actually works fine if the app hot reloads from my npm dev server, it reaches out to my API, which authorizes the request using the token, and sends back the correct data. The problem is when I manually reload the page, which causes this:
Uncaught (in promise) TypeError: Cannot read property 'getTokenSilently' of null
at Vue.getTokenSilently (authWrapper.js?de49:65)
at _callee$ (App.vue?234e:49)
Inside the authWrapper.js file (where the Auth0 client lives), the function call is here:
getTokenSilently(o) {
return this.auth0Client.getTokenSilently(o);
}
When I debug the call, "auth0Client" doesn't exist, which is why it's failing. What I can't understand is the correct way to ensure it does exist before I attempt to make the call. There's nothing in the samples that indicates the right way to do this. I tried putting my component code in different components and different Vue lifecycle hooks (created, beforeMount, mounted, etc), all with the same result. The client becomes available after 800 ms or so, but not when this code executes.
This is clearly a timing problem, but it's not clear to me how to tell my component code to sit and wait until this.auth0Client is non-null without doing something horrible and hacky like a setInterval.
I figured out a workaround for now, which I'll add as an answer in case anyone else has this issue, although it's not really the answer I want. Per the authGuard, you can use the exported "instance" from the authWrapper and watch its "loading" flag before executing your code that depends on the auth0Client being ready, like this:
import { getInstance } from "./auth/authWrapper";
// ... Vue component:
created() {
this.init(this.doSomethingWithAuth0Client);
},
methods: {
init(fn) {
// have to do this nonsense to make sure auth0Client is ready
var instance = getInstance();
instance.$watch("loading", loading => {
if (loading === false) {
fn(instance);
}
});
},
async doSomethingWithAuth0Client(instance) {
await instance.getTokenSilently().then((authToken) => {
// do authorized API calls with auth0 authToken here
});
}
}
It's hardly ideal, but it does work.

Categories

Resources