Giter VIP home page Giter VIP logo

Comments (15)

mayteio avatar mayteio commented on May 25, 2024

Hey @underfisk that's definitely not the intention - are you able to reproduce this in a codesandbox so I can have a look?

from use-pusher.

underfisk avatar underfisk commented on May 25, 2024

@mayteio I'll take a look later and see if i can replicate, right now i'm having this issue in production
My guess is that when i combine the channel + the event as in the docs, one of them unsubscribes and never comes back
It's not practical the child subscribe but it's a requirement that i have and its not supposed to not invoke the callback
Also, another thing is that internally there is no useCallback and when we create anonymous functions as the argument it will provoke a re-render of the hook and it shouldn't (useCallback/function reference is solving the issue)

from use-pusher.

mayteio avatar mayteio commented on May 25, 2024

OK great, if you can send an example I can take a look for you. Hard to say anything without code examples or reproducible CSB.

And yes, that's intentional. See docs:

Note: This will bind and unbind to the event on each render. You may want to memoise your callback with useCallback before passing it in if you notice performance issues.

from use-pusher.

underfisk avatar underfisk commented on May 25, 2024

@mayteio Ah ok i see. Regarding the demo i'll check it later

from use-pusher.

mayteio avatar mayteio commented on May 25, 2024

Cool, let me know how you go.

from use-pusher.

underfisk avatar underfisk commented on May 25, 2024

This is kinda erratic, in production and staging environment this is happening but locally it seems bulletproof so kinda hard to replicate but the main issue as i said its the consuming on the hook

This is the wrapper that i'm using to subscribe for a "project event"

export default function useProjectEvent<T = any>(name: string, onEventFn: (data: T) => void) {
	const project = useSelector((state: AppState) => state.table.project)
	const channel = useChannel(`private-project-${project.id}`)

	useEvent(channel, name, onEventFn)
}

As you can see there is a reducer subscription for project changes, in case you change project (to get notified on the new id)
Now this is how i invoke the useProjectEvent

const onProjectStarted = useCallback(() => {
	dispatch(UpdateProject('started', true))
}, [])
useProjectEvent('project.started', onProjectStarted)

That shown above is one custom hook and how i do invoke it but the issue here is the websocket receives the event but the provided callback is either invoked once OR never basically (Pusher is working also fine, the debug console shows correctly the events)

Now i have also a global wrapper which is used the same way (internally subscribing to a custom hook that simply subscribes to redux)

export default function usePusherEvent<T = any>(name: string, onEventFn: (data: T) => void, isPrivate = false) {
	const [profile] = useProfile()
	const channel = useChannel(isPrivate ? `private-${profile.user.email}` : `private-${profile.account._id}`)
	useEvent(channel, name, (payload: any) => {
		onEventFn(payload)
	})
}

Now i can have multiple guesses which are:

  1. The internal subscription on redux/custom hook unbinds the useEvent but that would not make any sense because its a re-render and as you said its supposed to subscribe back
  2. There is some internal issue with the plugin itself, you might have to replicate a custom hook that subscribes to redux or so and replicate this
  3. useChannel changes provoke a re-render that makes useEvent not subscribe back or vice versa which would be weird but its possible

I'm not sure if this helps you but it is a strange behaviour that i'm facing in production and its kinda erratic to replicate but this happens with this hooks (I haven't tested it using directly useChannel + useEvent outside because they would have also to depend on a private channel that has its info within redux)

from use-pusher.

mayteio avatar mayteio commented on May 25, 2024

Hmmm, frankly it's hard to say. I haven't explicitly looked into private channels here, working under the assumption they have similar requirements to presence channels (which are supported) as they both require auth.

How are you authenticating your private channel?

from use-pusher.

underfisk avatar underfisk commented on May 25, 2024

@mayteio Basically i have a custom route, nothing fancy its even a copy of what's in official pusher documentation. Now i see multiple auth HTTP request going, they return successfully, the event is on WS console as i said but the plugin does not consume it
Private channels is a must for us, they are very erratic and sometimes work and sometimes doesn't
From my perspective, my wrapper is fine and if plugin has its own bindings for mount/unmounting then it should be fine because it will not be constantly re-rendering to lose events

from use-pusher.

underfisk avatar underfisk commented on May 25, 2024

There might be an issue with my wrapper sharing channel. So basically I want a channel to live while the app is open because these channels are not temporary with the hook, what is happening is that when some component that uses my wrapper unmounts, it unbinds the channel everywhere which I thought this plugin would isolate but in reality, it is shared and that's why I lose subscriptions and the channel becomes "vacated".
Is there any alternative on this because it seems to a bug to me, my use case is pretty straightforward, having a channel that its lifetime is the application itself and not the component (As far as I'm concerned, the plugin only allow to subscribe into a channel if I pass the result of the hook but what if I want to re-use a channel and not allowing it to unsubscribe when the component re-renders?)

from use-pusher.

mayteio avatar mayteio commented on May 25, 2024

Hey @underfisk, did you solve this to close it? We use it in a similar use case and have the hook subscribed high up in the app hierarchy, so it rarely re-renders, therefore re-subscribes.

from use-pusher.

underfisk avatar underfisk commented on May 25, 2024

Yes i have manage to solve, the re-sub is not ideal because we have 2 channels that only close when you disconnect from the app. (organization channel and private user channel)
So what i did is basically use (usePusher hook) and not using (useChannel hook) by searching for the registered channels with usePusher in the client itself and bind but i will only cleanup in unmount/re-render the event subscription, not the channel.
With your hook if any of my components that use my organization channel were going to unmount and not mount back, the channel would end up being disconnected and the other components would lose its connectivity.
For temporary cases where you want the channel to unbind when component unmounts, useChannel suits but in our case we had to do a manual subscription at a HoC using usePusher and in each component only bind/unbind the events
Its kinda strange to explain but resumingly, we stop using (useChannel hook) due to what its doing internally, its not ideal having a re-subscription firing in often renderers, not at all

from use-pusher.

mayteio avatar mayteio commented on May 25, 2024

useChannel should only resubscribe when the channel name changes, as it subscribes inside an effect:

useEffect(() => {
/** Return early if there's no client */
if (!client) return;
/** Return early and warn if there's no channel */
if (!channelName) {
console.warn(NO_CHANNEL_NAME_WARNING);
return;
}
/** Subscribe to channel and set it in state */
const pusherChannel = client.subscribe(channelName);
setChannel(pusherChannel as T);
/** Cleanup on unmount/re-render */
return () => client?.unsubscribe(channelName);
}, [channelName, client]);

the pusher client is only re-created when any of the options change:

useEffect(() => {
// Skip creation of client if deferring, a value prop is passed, or config props are the same.
if (
!_PusherRuntime ||
defer ||
props.value ||
(dequal(previousConfig.current, props) && client !== undefined)
) {
return;
}
// @ts-ignore
setClient(new _PusherRuntime(clientKey, config));
}, [client, clientKey, props, defer]);

So I'm unsure why it's resubscribing you. If you can replicate it in code sandbox I'd be happy to look at it, otherwise I'm sorry it's not working as expected for you.

from use-pusher.

underfisk avatar underfisk commented on May 25, 2024

@mayteio As a fun fact, it is unsubscribing my channel when one component unmounts and the rest of components that use the same channel basically get "disconnected" from it, its like none is isolated.
Client might be changing in there, there is a dependency up there but well, when i removed useChannel it did fix my issue at some point
I can review it again and check the use case you said before, create an HoC with useChannel and a children component unmounting and see if it removes the other component channel subscription but in WS to pusher the last event before was "vacated" where it simply unsubscribes the room

from use-pusher.

underfisk avatar underfisk commented on May 25, 2024

@mayteio Since the last time i though the issue was fixed but it isn't. I still keep getting the pusher events on WS network but the events are not invoked from use-pusher. I find it weird but I think it would be great if you can provide internal logger so we could identify if its an early return or which condition is making it not reaching the consumer

from use-pusher.

softgiving-omer avatar softgiving-omer commented on May 25, 2024

We're sometimes facing the same problem. When I inspect the Network WS tab on the dev tools, I see that messages are arriving, however, the hook callback is not called.

from use-pusher.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.