State Management·续

override fun onMeetingRoomJoinCompleted(meeting: RealtimeKitClient) { Log.d("Meeting", "Joined the meeting") // Update UI to show meeting controls }

override fun onMeetingRoomJoinFailed(exception: Exception) { Log.e("Meeting", "Join failed: ${exception.message}") }

override fun onMeetingRoomLeaveStarted() { Log.d("Meeting", "Leave started") }

override fun onMeetingRoomLeft() { Log.d("Meeting", "Left the meeting") }

override fun onMeetingEnded() { Log.d("Meeting", "Meeting ended for all participants") }

override fun onActiveTabUpdate(activeTab: ActiveTab) { Log.d("Meeting", "Active tab changed: $activeTab") } })

// Listen for local participant state changes meeting.addSelfEventListener(object : RtkSelfEventListener { override fun onAudioUpdate(isEnabled: Boolean) { Log.d("Meeting", "Audio: ${if (isEnabled) "on" else "off"}") }

override fun onVideoUpdate(isEnabled: Boolean) { Log.d("Meeting", "Video: ${if (isEnabled) "on" else "off"}") }

override fun onRemovedFromMeeting() { Log.d("Meeting", "Removed from meeting by host") } }) } }


For iOS, implement event listener protocols and register them on the `meeting` object. Use `RtkMeetingRoomEventListener` for meeting lifecycle events and `RtkSelfEventListener` for local participant state changes.

```swift
// Listen for meeting room state changes
extension MeetingViewModel: RtkMeetingRoomEventListener {
    func onMeetingRoomJoinCompleted(meeting: RealtimeKitClient) {
        // Successfully joined the meeting (equivalent to 'joined' state)
    }

func onMeetingRoomLeft() {
        // Successfully left the meeting
    }

func onMeetingEnded() {
        // The meeting has ended for all participants (equivalent to 'ended' state)
    }

func onActiveTabUpdate(activeTab: ActiveTab) {
        // Active tab changed (e.g., chat, polls, participants)
        // Use this to sync your custom UI with the active sidebar section
    }
}

// Listen for local participant state changes
extension MeetingViewModel: RtkSelfEventListener {
    func onAudioUpdate(isEnabled: Bool) {
        // Audio toggled on/off
    }

func onVideoUpdate(isEnabled: Bool) {
        // Video toggled on/off
    }

func onRemovedFromMeeting() {
        // Local user was removed from the meeting by host
    }
}

// Register the listeners
meeting.addMeetingRoomEventListener(meetingRoomEventListener: self)
meeting.addSelfEventListener(selfEventListener: self)

For React Native, use the useRealtimeKitSelector hook to observe specific properties on the meeting object. This pattern is similar to the web Core SDK.

import { useEffect } from "react";
import { View, Text } from "react-native";
import {
    RealtimeKitProvider,
    useRealtimeKitClient,
    useRealtimeKitMeeting,
    useRealtimeKitSelector,
} from "@cloudflare/realtimekit-react-native";
import {
    RtkUIProvider,
    RtkMeeting,
} from "@cloudflare/realtimekit-react-native-ui";

function App() {
    const [meeting, initMeeting] = useRealtimeKitClient();

useEffect(() => {
        initMeeting({
            authToken: "<participant_auth_token>",
            defaults: { audio: true, video: true },
        });
    }, []);

return (
        <RealtimeKitProvider value={meeting}>
            <RtkUIProvider>
                <MeetingWithState />
            </RtkUIProvider>
        </RealtimeKitProvider>
    );
}

function MeetingWithState() {
    const { meeting } = useRealtimeKitMeeting();

// Use selectors to observe meeting state
    const roomState = useRealtimeKitSelector((m) => m.self.roomState);
    const audioEnabled = useRealtimeKitSelector((m) => m.self.audioEnabled);
    const videoEnabled = useRealtimeKitSelector((m) => m.self.videoEnabled);

useEffect(() => {
        console.log("Room state:", roomState);
        console.log("Audio:", audioEnabled);
        console.log("Video:", videoEnabled);
    }, [roomState, audioEnabled, videoEnabled]);

return (
        <View>
            {meeting && <RtkMeeting meeting={meeting} showSetupScreen={true} />}

{/* Use state to build custom UI */}
            <View>
                <Text>Room State: {roomState}</Text>
                <Text>Audio: {audioEnabled ? "On" : "Off"}</Text>
                <Text>Video: {videoEnabled ? "On" : "Off"}</Text>
            </View>
        </View>
    );
}

Alternative: Using Event Listeners

You can also use event-based listeners for more fine-grained control, similar to the web Core SDK:

import { useEffect } from "react";

function MeetingEvents() {
    const { meeting } = useRealtimeKitMeeting();

useEffect(() => {
        if (!meeting) return;

const handleRoomJoined = () => {
            console.log("Successfully joined the meeting");
        };

const handleRoomLeft = ({ state }) => {
            if (state === "ended") {
                console.log("Meeting ended");
            }
        };

meeting.self.on("roomJoined", handleRoomJoined);
        meeting.self.on("roomLeft", handleRoomLeft);

return () => {
            meeting.self.removeListener("roomJoined", handleRoomJoined);
            meeting.self.removeListener("roomLeft", handleRoomLeft);
        };
    }, [meeting]);

return null;
}

State Properties

The rtkStatesUpdate event provides detailed information about the UI Kit's internal state. Key properties include:

  • meeting: Current meeting state - 'idle', 'setup', 'joined', 'ended', or 'waiting'
  • activeSidebar: Whether the sidebar is currently open (boolean)
  • sidebar: Current sidebar section - 'chat', 'participants', 'polls', 'plugins', etc.
  • activeScreenShare: Whether screen sharing UI is active (boolean)
  • activeMoreMenu: Whether the more menu is open (boolean)
  • activeSettings: Whether settings panel is open (boolean)
  • viewType: Current video grid view type (string)
  • prefs: User preferences object (e.g., mirrorVideo, muteNotificationSounds)
  • roomLeftState: State when leaving the room
  • activeOverlayModal: Active overlay modal configuration object
  • activeConfirmationModal: Active confirmation modal configuration object
  • And many more UI state properties

Note

These are UI Kit internal states for managing the interface. For meeting data like participants, active speaker, or recording status, use the Core SDK's meeting object directly.

On mobile platforms, state is observed through Core SDK event listeners rather than a single state object. The key event listeners and their callbacks include:

RtkMeetingRoomEventListener - Meeting lifecycle:

  • onMeetingRoomJoinStarted: Meeting join process has started
  • onMeetingRoomJoinCompleted: Successfully joined the meeting
  • onMeetingRoomJoinFailed: Meeting join failed (provides exception details)
  • onMeetingRoomLeaveStarted: Leave process has started
  • onMeetingRoomLeft: Successfully left the meeting
  • onMeetingEnded: Meeting ended for all participants
  • onActiveTabUpdate: Active sidebar tab changed (chat, polls, participants)

RtkSelfEventListener - Local participant:

  • onAudioUpdate: Audio toggled on or off
  • onVideoUpdate: Video toggled on or off
  • onRemovedFromMeeting: Local user was removed by host

RtkParticipantsEventListener - Remote participants:

  • onParticipantJoin: A participant joined the meeting
  • onParticipantLeave: A participant left the meeting
  • onActiveParticipantsChanged: Active participants list changed
  • onAudioUpdate: A remote participant's audio state changed
  • onVideoUpdate: A remote participant's video state changed

Note

For the full list of event listeners and their callbacks, refer to the Core SDK meeting object documentation.

On React Native, use the useRealtimeKitSelector hook to observe specific properties on the meeting object. Key properties include:

  • m.self.roomState: Current room state ( 'init', 'joined', 'left', etc.)
  • m.self.audioEnabled: Whether local audio is enabled (boolean)
  • m.self.videoEnabled: Whether local video is enabled (boolean)
  • m.self.screenShareEnabled: Whether screen share is active (boolean)
  • m.self.name: Local participant display name
  • m.self.id: Local participant peer ID
  • m.participants.joined: List of joined participants
  • m.participants.active: List of active participants

Note

For the full list of available properties, refer to the Core SDK meeting object documentation.

Best Practices

  • Store states appropriately: Use React's useState hook or a state management library (like Zustand or Redux) for React apps. For vanilla JavaScript, use a reactive state management solution or simple object storage.
  • Avoid excessive re-renders: Only update your UI when necessary. In React, consider using useMemo or useCallback to optimize performance.
  • Access nested properties safely: Always check if nested properties exist before accessing them (e.g., states.sidebar, states.prefs?.mirrorVideo).
  • Use states for conditional rendering: Leverage the UI states to show/hide UI elements or respond to interface changes (e.g., showing custom indicators when states.activeScreenShare is true).
  • Understand the difference: rtkStatesUpdate provides UI Kit internal states for interface management. For meeting data (participants, active speaker, recording status), use the Core SDK's meeting object and its events directly.

  • Remove listeners on cleanup: Always remove event listeners in onDestroy() to prevent memory leaks. Store listener references so you can unregister them later.

  • Use appropriate threading: Event listener callbacks may fire on background threads. Use runOnUiThread or post to the main handler when updating UI elements.
  • Store state in observable patterns: Use LiveData, StateFlow, or MutableState (Compose) to propagate state changes to your UI reactively.
  • Understand the difference: Event listeners provide meeting lifecycle and participant state changes. The UI Kit manages its own internal UI state separately.

  • Remove listeners on cleanup: Always remove event listeners when your view controller or view model is deallocated to prevent retain cycles and memory leaks.

  • Use @Published for reactive UI: In SwiftUI, mark state properties as @Published in your ObservableObject to automatically re-render views when meeting state changes.
  • Handle threading: Event listener callbacks may fire on background threads. Use DispatchQueue.main.async when updating UI elements from callbacks.
  • Understand the difference: Event listeners provide meeting lifecycle and participant state changes. The UI Kit manages its own internal UI state separately.

  • Use selectors for efficiency: The useRealtimeKitSelector hook only re-renders your component when the selected value changes. Select only the specific properties you need rather than the entire meeting object.

  • Clean up event listeners: When using meeting.self.on() event listeners, always return a cleanup function from useEffect that calls removeListener.
  • Combine with useMemo and useCallback: Use React memoization hooks to prevent unnecessary re-renders when meeting state changes frequently.
  • Understand the difference: useRealtimeKitSelector provides access to Core SDK meeting state (participants, media, room state). The UI Kit handles its own internal UI state through the RtkMeeting component.

Was this helpful?

YesNo

On this page

State Management·续 - 图1Docs

{"@context":"https://schema.org","@type":"WebPage","@id":"https://developers.cloudflare.com/realtime/realtimekit/humans/ui-kit/state-management/#page","headline":"State Management","description":"Manage and synchronize meeting state across RealtimeKit UI Kit components.","url":"https://developers.cloudflare.com/realtime/realtimekit/humans/ui-kit/state-management/","inLanguage":"en","image":"https://developers.cloudflare.com/realtime/realtimekit/humans/ui-kit/state-management/og.png?v=b4ad3d5fe2eeda63","dateModified":"2026-10-19","publisher":{"@type":"Organization","name":"Cloudflare","description":"One platform for your apps, agents, and workforce. Build, secure, and scale without managing infrastructure","url":"https://www.cloudflare.com/","sameAs":["https://github.com/cloudflare","https://www.linkedin.com/company/cloudflare","https://x.com/cloudflare"],"logo":{"@type":"ImageObject","url":"https://developers.cloudflare.com/logo.svg"},"address":{"@type":"PostalAddress","streetAddress":"101 Townsend St","addressLocality":"San Francisco","addressRegion":"CA","postalCode":"94107","addressCountry":"US"},"contactPoint":[{"@type":"ContactPoint","contactType":"Customer Support","url":"https://support.cloudflare.com/","availableLanguage":["English"]},{"@type":"ContactPoint","contactType":"Sales","url":"https://www.cloudflare.com/contact/","availableLanguage":["English"]}]},"isPartOf":{"@type":"WebSite","@id":"https://developers.cloudflare.com/#website","name":"Cloudflare Docs","url":"https://developers.cloudflare.com/"}}


description: Review how long RealtimeKit stores meeting chat, recordings, analytics, and webhook logs. title: Data retention image: https://developers.cloudflare.com/realtime/realtimekit/platform/data-retention/og.png?v=98375a02dd8e78f8


Skip to content

Documentation Index
Fetch the complete documentation index at: https://developers.cloudflare.com/realtime/llms.txt
Use this file to discover all available pages before exploring further.