Closed iamacatperson closed 4 years ago
Any update on this?
@iamacatperson you should move chat initialization logic to async componentDidMount
!!
import React, { Component } from "react";
import {
Chat,
Channel,
Window,
MessageList,
MessageInput,
MessageLivestream,
ChannelHeader,
Thread
} from "stream-chat-react";
import { StreamChat } from "stream-chat";
class ChatComponent extends Component {
state = {
chatClient: null,
channel: null;
viewers: []
};
async componentDidMount() {
const user = // some user object from local storage //
const chatClient = new StreamChat(process.env.STREAM_API_KEY);
await chatClient.setUser(
{
id: user.id,
name: user.name
},
OUR_STREAM_TOKEN
);
const channel = this.chatClient.channel(
"livestream",
process.env.STREAM_CHANNEL_ID
);
await channel.watch();
this.setState({
chatClient,
channel
});
}
componentWillUnmount() {
this.chatClient.off("user.presence.changed");
}
getViewers = async viewerIds => {
const response = await this.chatClient.queryUsers(
{ id: { $in: viewerIds } },
{ last_active: -1 },
{
presence: true,
limit: 10,
offset: 0
}
);
this.setState({ viewers: response.users });
};
render() {
if (!this.state.chatClient) return null;
const { watcher_count } = this.state.channel.state;
return (
<div className="chat">
{/** i need to display the count outside the <Chat> component */}
<div className="chat__header">{watcher_count}</div>{" "}
<Chat client={this.state.chatClient} theme={"livestream light"}>
<Channel channel={this.state.channel} Message={MessageLivestream}>
<ChannelHeader live></ChannelHeader>{" "}
{/** within here, it shows the actual count */}
<Window hideOnThread>
<MessageList></MessageList>
<MessageInput />
</Window>
<Thread fullWidth />
</Channel>
</Chat>
</div>
);
}
}
export default ChatComponent;
NOTE I haven't exactly tested the code, but you get the idea I suppose :)
@vishalnarkhede I tried the above implementation and it solves the issue with watcher_count
value showing up as 0
. I can now see the actual value on page load. However, the watcher count still doesn't update automatically whenever a new user / member joins the channel. The person needs to type something on the chat first, then the watcher_count
updates.
As you can see, I have this implementation in the componentDidMount()
method:
this.state.chatClient.on("user.presence.changed", event => {
console.log(event);
// also, update online / offline user listing
});
this.state.channel.on(event => {
console.log("event", event);
});
When someone logs-in/out of the application, user.presence.changed
is detected, and I can see the log for that event in the console that a person became "offline/online". Hence, am able to show in real-time which people are online/offline. However, channel doesn't detect any change / log anything. The watcher_count
remains the same (not real-time).
What could be the issue for that?
I also do not understand this part in the docs under "Watcher Count" (seems to have been updated recently):
let channel = Client.shared.channel(type: .messaging, id: "general")
let subscription = channel.subscribeToWatcherCount { count in
// handle count
}
// Cancel subscription when you want to stop receiving events
subscription.cancel()
I am getting Unhandled Rejection (TypeError): Cannot read property 'channel' of undefined
. There seems to be no shared
prop in client object. And also the let subscription
part seems to have typo?
let channel = Client.shared.channel(type: .messaging, id: "general") let subscription = channel.subscribeToWatcherCount { count in // handle count } // Cancel subscription when you want to stop receiving events subscription.cancel()
@iamacatperson this is part of swift doc. Apologies for confusion, we will fix that asap. Please don't use it for js.
When someone logs-in/out of the application, user.presence.changed is detected, and I can see the log for that event in the console that a person became "offline/online". Hence, am able to show in real-time which people are online/offline. However, channel doesn't detect any change / log anything. The watcher_count remains the same (not real-time).
This is expected since react component is not aware of changes inside channel object. So you need to explicitly call setState here:
this.state.chatClient.on("user.presence.changed", event => {
this.setState({
channel: this.state.channel
})
});
@vishalnarkhede The watcher count still remains unchanged when I console.log the channel state on presence change.
this.state.chatClient.on("user.presence.changed", event => {
console.log(this.state.channel); // shows the unchanged/old watcher_count
this.setState({
channel: this.state.channel
})
});
Is there any other way?
Hey @iamacatperson I missed one thing in my last reply (sorry for that)
Actually you are using wrong event for watcher_count. user.presence.changed
event means, some user has established a websocket connection. It doesn't mean he has started watching a channel.
To check for watch, you need user.watching.start
event:
So for your case, it would be
this.state.channel.on("user.watching.start", event => {
this.setState({
channel: this.state.channel
})
});
watcher_count
is the number of users who are currently watching the particular channel. Its a subset of number of members who are currently online :)
@vishalnarkhede I tried adding:
this.state.channel.on("user.watching.start", event => {
console.log(event);
console.log(this.state.channel)
this.setState({
channel: this.state.channel
})
});
...And the event is never triggered / logged when someone joins. What part of the code actually triggers a user watch event? Am I missing that in my code (in my first post)?
@iamacatperson this event gets triggered when user on other end does channel.watch()
@vishalnarkhede Yes, I have that in componentDidMount()
.
async componentDidMount() {
const user = // user object //
const chatClient = new StreamChat(envs.STREAM_API_KEY);
await chatClient.setUser(
{
id: user.id,
name: user.name
},
OUR_STREAM_TOKEN
);
const channel = chatClient.channel("livestream", STREAM_CHANNEL_ID);
await channel.watch();
this.setState(
{
chatClient,
channel
}
);
this.state.chatClient.on("user.presence.changed", event => {
// console.log(event);
// console.log(this.state.channel);
});
this.state.channel.on("user.watching.start", event => {
console.log("channel event");
console.log(event); // nothing is triggered
console.log(this.state.channel);
this.setState({
channel: this.state.channel
});
});
}
Still the watch event is not triggered. What else could be the issue?
Can you check your chat config on stream dashboard?
@iamacatperson missed an important thing here. You need to request presence explicitly
await channel.watch({ presence: true });
https://getstream.io/chat/docs/presence_format/?language=js#listening-to-presence-changes
It finally worked. 👍
I haven't added the ({ presence: true });
yet but previously "Search" and "Connect Events" were off. It didn't occur to me that it's a 'connection' event. Thanks a lot @vishalnarkhede.
@iamacatperson glad that it worked :)
Yeah I think it'd be good to add in the documentation to make sure 'connection events' are turned on in the settings. That was the only missing piece, I think.
The JS documentation still has the Swift code. I was very confused until I found this issue
I am facing two issues with
watch_count
.<MessageHeader>
component, when a new member joins, thewatch_count
value only updates when the new member has typed something in the channel. It doesn't update automatically when a new member joins.watcher_count
(inconst { watcher_count } = this.channel.state
) returns0
if used outside the<Chat>
component.Please see below code structure:
Am I missing anything?