Performance is a crucial aspect of any mobile application, especially when preparing for release. A smooth and responsive user experience ensures that your users have a pleasant time interacting with your app.

Same happened with me at work. We are developing our application in react native but to my surprise, it could not handle much stuff going on when compared to the web version.

In this blog post, we'll explore three effective methods to optimize the performance of your React Native application.

1. Utilizing React.memo
One common performance bottleneck in React Native applications is unnecessary re-rendering. Even when no actual changes occur, components might re-render, leading to a sluggish user interface. To address this issue, React provides a useful tool called React.memo.

How to Use React.memo
Wrap your component with React.memo to memoize it, preventing re-renders unless the props change. Here's a quick example:

import React from 'react';

const MyComponent = React.memo(({ data }) => {
  // Your component logic here
});

export default MyComponent;
This ensures that the component only re-renders when the props it receives change, significantly improving performance.

2. Leveraging useCallback for Referential Equality
In scenarios where memoization breaks, especially when dealing with functions, the useCallback hook comes to the rescue. When a component relies on referential equality, using useCallback prevents unnecessary re-renders.

How to Use useCallback
import React, { useCallback } from 'react';

const MyComponent = ({ onClick }) => {
  const memoizedClick = useCallback(() => {
    // Your click handler logic here
  }, [/* dependencies */]);

  return (
    <button onClick={memoizedClick}>Click me</button>
  );
};

export default MyComponent;
By specifying dependencies, you ensure that the callback remains referentially equal unless the dependencies change.

3. Optimizing Expensive Functions with useMemo
Another common scenario involves optimizing the performance of expensive functions within components. The useMemo hook helps achieve this by memoizing the result of a function and recalculating it only when the dependencies change.

How to Use useMemo
import React, { useMemo } from 'react';

const MyComponent = ({ data }) => {
  const memoizedResult = useMemo(() => {
    // Expensive function logic here
    return result;
  }, [/* dependencies */]);

  return (
    <div>{memoizedResult}</div>
  );
};

export default MyComponent;
By carefully selecting dependencies, you control when the expensive function is recomputed, enhancing overall performance.


Based on these recommendations:

make the changes in the following code to optimize it and avoid unnecessary re-renders
import {AudioSession, useParticipant, useRoom} from '@livekit/react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';
import {createMaterialTopTabNavigator} from '@react-navigation/material-top-tabs';
import axios from 'axios';
import type {LocalParticipant} from 'livekit-client';
import {
  DataPacket_Kind,
  RemoteParticipant,
  Room,
  RoomEvent,
  TrackPublication,
} from 'livekit-client';
import React, {useEffect, useRef, useState} from 'react';
import {
  BackHandler,
  Image,
  Keyboard,
  ScrollView,
  TouchableWithoutFeedback,
  useWindowDimensions,
  View,
} from 'react-native';
import {
  ActivityIndicator,
  Button,
  Card,
  Chip,
  IconButton,
  Menu,
  SegmentedButtons,
  Text,
  TextInput,
} from 'react-native-paper';
import RenderHTML from 'react-native-render-html';
import ADIcon from 'react-native-vector-icons/AntDesign';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import ChatView from '../../components/layout/ChatView';
import ExitDialog from '../../components/layout/ExitDialog';
import ParticipantCard from '../../components/layout/ParticipantCard';
import TopChip from '../../components/layout/TopChip';
import {StageView} from '../../components/StageView';
import RazorpayInit from '../../lib/razorpay';
// @ts-ignore
import {API_URL} from '@env';
import analytics from '@react-native-firebase/analytics';
import swr from 'swr';
import mixpanel, {mixpanelBtnClick} from '../../lib/mixpanel';
import {
  widthPercentageToDP as w,
  heightPercentageToDP as h,
} from 'react-native-responsive-screen';
import PIPCard from '../../lib/PIPCard';

const fetcher = async (url: string) => {
  const token = await AsyncStorage.getItem('token');

  return axios
    .get(url, {
      headers: {
        Authorization: `Bearer ${token}`,
      },
    })
    .then(res => res.data)
    .catch(err => err.response.data);
};

export default function LiveClass({navigation, route}: any) {
  const [showOptions, setShowOptions] = useState(true);
  const [message, setMessage] = useState('');
  const [messages, setMessages] = useState<any[]>([]);
  const [unreadMessages, setUnreadMessages] = useState(0);
  const [dialogVisible, setDialogVisible] = useState(false);
  const [isScrolling, setIsScrolling] = useState(false);
  const [audioMode, setAudioMode] = useState<'speaker' | 'earpiece'>('speaker');
  const [page, setPage] = useState(0);
  const [loading, setLoading] = useState(false);
  const [messageRecipient, setMessageRecipient] = useState<string>('public');
  const [expanded, setExpaned] = useState(false);
  const [messageLoading, setMessageLoading] = useState(false);
  const [isPipModeEnabled, setIsPipModeEnabled] = useState(false);
  const [pipModeDelay, setPipModeDelay] = useState(false);
  const Tab = createMaterialTopTabNavigator();
  const {url, token, masterclassId} = route.params;
  const localInputRef = useRef<any>();

  const [room] = useState(
    () =>
      new Room({
        adaptiveStream: {pixelDensity: 'screen'},
        // publishDefaults: { simulcast: false },
        audioCaptureDefaults: {
          autoGainControl: true,
          echoCancellation: true,
          noiseSuppression: true,
        },
        videoCaptureDefaults: {
          facingMode: 'user',
        },
        publishDefaults: {
          simulcast: false,
        },
        reconnectPolicy: {
          nextRetryDelayInMs: (context): number | null => {
            if (context.retryCount > 10) {
              return null;
            }

            console.log(
              `retrying connection: retries: ${context.retryCount} sec: ${
                context.elapsedMs / 1000
              } `,
            );
            return 3000; //retry every 3 seconds
          },
        },
        disconnectOnPageLeave: true,
      }),
  );

  const [isMuteButtonVisible, setIsMuteButtonVisible] = useState(false);

  const {
    data: masterclassInfo,
    error,
    isLoading,
    mutate,
  } = swr(
    `fetchMasterclassInfo-${masterclassId}`,
    () =>
      fetcher(
        `${API_URL}/masterclasses/app/masterclass-info?mid=${masterclassId}`,
      ),
    {
      refreshInterval: 10000,
    },
  );

  const keyboardDidHideCallback = () => {
    localInputRef.current?.blur?.();
  };

  useEffect(() => {
    const keyboardDidHideSubscription = Keyboard.addListener(
      'keyboardDidHide',
      keyboardDidHideCallback,
    );

    return () => {
      keyboardDidHideSubscription?.remove();
    };
  }, []);

  const {participants} = useRoom(room);

  const {cameraPublication, microphonePublication} = useParticipant(
    room.localParticipant,
  );

  function isTrackEnabled(pub?: TrackPublication): boolean {
    return !(pub?.isMuted ?? true);
  }

  type DataSendOptions = {
    kind?: DataPacket_Kind;
    destination?: string[];
  };

  const DataTopic = {
    CHAT: 'lk-chat-topic',
  } as const;

  async function sendMessageToClient(
    localParticipant: LocalParticipant,
    payload: Uint8Array,
    topic?: string,
    options: DataSendOptions = {},
  ) {
    const {kind, destination} = options;

    await localParticipant.publishData(
      payload,
      kind ?? DataPacket_Kind.RELIABLE,
      {
        destination,
        topic,
      },
    );
  }

  async function sendMessage() {
    if (!message) {
      return;
    }
    setShowOptions(true);
    setMessageLoading(true);
    try {
      let encoder = new TextEncoder();
      const timestamp = Date.now();
      const encodedMsg = encoder.encode(JSON.stringify({timestamp, message}));
      const adminRecipients = participants.filter(p => {
        const metaData = JSON.parse(p.metadata!);
        return (
          metaData.isAdmin && p.identity !== room.localParticipant.identity
        );
      });
      if (messageRecipient == 'admin') {
        await sendMessageToClient(
          room.localParticipant,
          encodedMsg,
          DataTopic.CHAT,
          {
            kind: DataPacket_Kind.RELIABLE,
            destination: adminRecipients.map(p => p.sid),
          },
        );
        setMessages(messages => [
          ...messages,
          {sender: 'You (to admins)', message: message},
        ]);
      } else {
        await sendMessageToClient(
          room.localParticipant,
          encodedMsg,
          DataTopic.CHAT,
          {
            kind: DataPacket_Kind.RELIABLE,
          },
        );
        setMessages(messages => [
          ...messages,
          {sender: 'You', message: message},
        ]);
      }
      setMessage('');
    } catch (e) {
      console.log(e);
    } finally {
      setMessageLoading(false);
    }
  }

  async function sendLike() {
    setMessageLoading(true);
    try {
      const user = await AsyncStorage.getItem('user').then(
        user => JSON.parse(user || '{}')?.data,
      );
      mixpanelBtnClick({
        btnType: 'thumbs_up',
        app: masterclassInfo?.data?.masterclass?.title,
        user: user,
      });
      let encoder = new TextEncoder();
      const timestamp = Date.now();
      const encodedMsg = encoder.encode(
        JSON.stringify({timestamp, message: '👍🏻'}),
      );
      await sendMessageToClient(
        room.localParticipant,
        encodedMsg,
        DataTopic.CHAT,
        {
          kind: DataPacket_Kind.RELIABLE,
        },
      );
      setMessages(messages => [...messages, {sender: 'You', message: '👍🏻'}]);
      setIsScrolling(false);
      setUnreadMessages(unreadMessages + 1);
    } catch (e) {
      console.log(e);
    } finally {
      setMessageLoading(false);
    }
  }

  useEffect(() => {
    AudioSession.selectAudioOutput(audioMode);
  }, [audioMode]);

  useEffect(() => {
    let connect = async () => {
      try {
        await AudioSession.configureAudio({
          android: {
            preferredOutputList: [
              'bluetooth',
              'headset',
              'speaker',
              'earpiece',
            ],
            audioFocusMode: 'gain',
            audioMode: 'normal',
          },
        });
        await AudioSession.startAudioSession();
        await room.connect(url, token, {
          autoSubscribe: true,
        });
      } catch (error: any) {
        console.log(error);
      }
    };
    connect();
    return () => {
      room.disconnect();
      AudioSession.stopAudioSession();
    };
  }, [url, token, room]);

  useEffect(() => {
    if (room.localParticipant.metadata) {
      const metadata = JSON.parse(room.localParticipant.metadata);
      if (metadata?.isAdmin || metadata?.canSpeak) {
        setIsMuteButtonVisible(true);
      }
      if (!metadata.canSpeak) {
        setIsMuteButtonVisible(false);
      }
    }
  }, [room?.localParticipant?.metadata]);

  useEffect(() => {
    if (room.metadata) {
      const pinnedMessages = JSON.parse(room.metadata).pinnedMessages;
    }
  }, [room.metadata]);
  const width = useWindowDimensions().width;

  useEffect(() => {
    const dataReceived = (
      payload: Uint8Array,
      participant?: RemoteParticipant,
    ) => {
      //@ts-ignore
      let decoder = new TextDecoder('utf-8');
      let data = JSON.parse(decoder.decode(payload));
      if (data?.type == 'pin') {
        return;
      }
      if (data?.type == 'action') {
        if (data?.payload.id == room.localParticipant.identity) {
          if (data?.payload?.action == 'mute') {
            setIsMuteButtonVisible(false);
            room.localParticipant.setMicrophoneEnabled(false);
          }
          if (data?.payload?.action == 'unmute') {
            setIsMuteButtonVisible(true);
          }
        }
        return;
      }

      setMessages(messages => [
        ...messages,
        {sender: participant?.name ?? 'You', message: data.message},
      ]);
      setUnreadMessages(unreadCnt => unreadCnt + 1);
    };
    room.on(RoomEvent.DataReceived, dataReceived);

    return () => {
      room.off(RoomEvent.DataReceived, dataReceived);
    };
  }, [room]);

  useEffect(() => {
    const backHandler = BackHandler.addEventListener(
      'hardwareBackPress',
      () => {
        setDialogVisible(true);
        return true;
      },
    );
    return () => {
      backHandler.remove();
    };
  }, []);

  useEffect(() => {
    const timer = setTimeout(() => {
      setPage(0);
    }, 5000);
    return () => clearTimeout(timer);
  }, [page]);

  useEffect(() => {
    if (!isPipModeEnabled) {
      setTimeout(() => {
        setPipModeDelay(false);
      }, 10);
    } else {
      setPipModeDelay(true);
    }
  }, [isPipModeEnabled]);

  const buttons = masterclassInfo?.data?.bootcamp?.bundleBootcamp
    ? [
        {
          value: masterclassInfo?.data?.bootcamp?.id,
          label: `Enroll Now - ₹${masterclassInfo?.data?.bootcamp?.discountedPrice?.toLocaleString(
            'en-IN',
          )}`,
          labelStyle: {
            color: 'white',
          },
        },
        {
          value: masterclassInfo?.data?.bootcamp?.bundleBootcamp?.id,
          label: `Enroll Now - ₹${masterclassInfo?.data?.bootcamp?.bundleBootcamp?.discountedPrice?.toLocaleString(
            'en-IN',
          )}`,
          labelStyle: {
            color: 'white',
          },
        },
      ]
    : [
        {
          value: masterclassInfo?.data?.bootcamp?.id,
          label: `Enroll Now - ₹${masterclassInfo?.data?.bootcamp?.discountedPrice?.toLocaleString(
            'en-IN',
          )}`,
          labelStyle: {
            color: 'white',
          },
          style: {
            borderWidth: 0,
          },
        },
      ];

  if (participants.length === 0 || participants.length === 1) {
    return (
      <View className="h-screen items-center justify-center p-8">
        <View className="rounded-xl overflow-hidden">
          <View className="w-72 aspect-video items-center justify-center">
            <Image
              source={require('../../assets/img/loading.gif')}
              className="aspect-video w-full h-full object-cover"
            />
          </View>
        </View>

        <Text className="text-black text-xl mt-2 text-center">
          You're in waiting room. Wait for the meeting to start.
        </Text>
        <ExitDialog
          exitFn={async () => {
            room.disconnect();
            const user = await AsyncStorage.getItem('user').then(
              user => JSON.parse(user || '{}')?.data,
            );
            mixpanelBtnClick({
              btnType: 'leave_meeting',
              app: masterclassInfo?.data?.masterclass?.title,
              user: user,
            });
            analytics().logEvent('leave_meeting', {
              title: masterclassInfo?.data?.masterclass?.title,
            });
            setDialogVisible(false);
            navigation.pop();
          }}
          visible={dialogVisible}
          setVisible={setDialogVisible}
          title="Leave Meeting"
          content="Are you sure you want to leave the meeting?"
        />
      </View>
    );
  }

  return (
    <PIPCard
      isPipModeEnabled={isPipModeEnabled}
      setIsPipModeEnabled={setIsPipModeEnabled}
      pipComponent={<StageView participants={participants} isPIP={true} />}>
      <View className="flex-1 bg-white">
        <TouchableWithoutFeedback onPress={() => Keyboard.dismiss()}>
          <>
            <TopChip
              showDialog={() => setDialogVisible(true)}
              audioMode={audioMode}
              setAudioMode={setAudioMode}>
              {(masterclassInfo?.data?.masterclass?.title.split(
                'Masterclass on',
              )[1]?.length > 30
                ? masterclassInfo?.data?.masterclass?.title
                    .split('Masterclass on')[1]
                    ?.slice(0, 30) + '...'
                : masterclassInfo?.data?.masterclass?.title
                    .split('Masterclass on')[1]
                    ?.slice(0, 30)) ??
                masterclassInfo?.data?.masterclass?.title}
            </TopChip>
            <View className="flex-0 relative w-screen">
              {page !== 0 && (
                <IconButton
                  icon={'arrow-left'}
                  mode="outlined"
                  className="absolute -left-1 top-6 z-50 bg-white"
                  iconColor="black"
                  size={12}
                  onPress={() => setPage(page - 1)}
                />
              )}
              <ScrollView horizontal className="flex-row mx-auto">
                {pipModeDelay && participants
                  .slice(3 * page, 3 * (page + 1))
                  .filter(participant => {
                    return (
                      JSON.parse(participant?.metadata ?? '{}')?.isAdmin ||
                      participant.isLocal
                    );
                  })
                  .map((participant, index) => (
                    <ParticipantCard
                      key={index}
                      participant={participant}
                      inList
                    />
                  ))}
              </ScrollView>
              {page < Math.floor(participants.length / 3) - 1 && (
                <IconButton
                  mode="outlined"
                  icon={'arrow-right'}
                  className="absolute -right-1 top-6 z-50 bg-white"
                  iconColor="black"
                  size={12}
                  onPress={() => setPage(page + 1)}
                />
              )}
            </View>
            <View
              className={`w-full relative transition-all duration-500 z-10 h-72 mt-2`}>
              <View className="flex-row absolute top-2 px-2 w-full justify-between z-20">
                <Chip
                  icon={() => (
                    <Icon name="account-outline" size={12} color="red" />
                  )}
                  className="bg-white/60 rounded-full w-fit h-6 items-center justify-center"
                  textStyle={{color: 'black', marginVertical: 0, fontSize: 12}}
                  compact>
                  {participants.length * 2}
                </Chip>
                <Chip
                  icon={() => <Icon name="record" size={12} color="red" />}
                  className="bg-white/60 rounded-full w-fit h-6 items-center justify-center"
                  textStyle={{color: 'black', marginVertical: 0, fontSize: 12}}
                  compact>
                  LIVE
                </Chip>
              </View>

              <StageView participants={participants} />
            </View>
            {masterclassInfo?.data?.metaData?.isEnrollNowButtonVisible ? (
              <Tab.Navigator
                initialRouteName="Chat"
                screenOptions={{
                  tabBarActiveTintColor: '#000000',
                  tabBarLabelStyle: {fontSize: 12, textTransform: 'none'},
                  tabBarIndicatorStyle: {backgroundColor: '#000000'},
                }}>
                <Tab.Screen
                  name="Chat"
                  children={() => (
                    <ChatView
                      unreadMessages={unreadMessages}
                      setUnreadMessages={setUnreadMessages}
                      messages={messages}
                      isScrolling={isScrolling}
                      setIsScrolling={setIsScrolling}
                    />
                  )}
                />
                <Tab.Screen
                  name="Overview"
                  children={() => (
                    <ScrollView className="bg-white flex-1 p-4">
                      <RenderHTML
                        source={{
                          html: masterclassInfo?.data?.bootcamp
                            ?.longDescription,
                        }}
                        contentWidth={width}
                        baseStyle={{
                          color: '#000',
                          fontSize: 16,
                        }}
                      />
                    </ScrollView>
                  )}
                />
                <Tab.Screen
                  name="Curriculum"
                  children={() => (
                    <ScrollView className="bg-white flex-1 p-4">
                      {masterclassInfo?.data?.sessions?.map(
                        (
                          session: {
                            title: string;
                            description: string;
                          },
                          index: React.Key | null | undefined,
                        ) => {
                          return (
                            <Card className="bg-white shadow-none" key={index}>
                              <Card.Title
                                titleStyle={{color: '#000'}}
                                title={session.title}
                              />
                              <Card.Content>
                                <Text className="text-black">
                                  {session.description}
                                </Text>
                              </Card.Content>
                            </Card>
                          );
                        },
                      )}
                    </ScrollView>
                  )}
                />
                <Tab.Screen
                  name="Teacher"
                  children={() => (
                    <ScrollView className="bg-white flex-1 p-4">
                      <RenderHTML
                        source={{
                          html: masterclassInfo?.data?.teacher?.bio,
                        }}
                        contentWidth={width}
                        baseStyle={{
                          color: '#000',
                          fontSize: 16,
                        }}
                      />
                    </ScrollView>
                  )}
                />
              </Tab.Navigator>
            ) : (
              <>
                <ChatView
                  unreadMessages={unreadMessages}
                  setUnreadMessages={setUnreadMessages}
                  messages={messages}
                  isScrolling={isScrolling}
                  setIsScrolling={setIsScrolling}
                />
              </>
            )}
            <View
              className={`bg-black z-50 ${
                masterclassInfo?.data?.metaData?.isEnrollNowButtonVisible
                  ? 'border-2'
                  : ''
              } rounded-t-3xl ${!showOptions ? '-mt-24' : ''}`}>
              {masterclassInfo?.data?.metaData?.isEnrollNowButtonVisible && (
                <View
                  style={{
                    width: width - 4,
                  }}
                  className="items-center justify-center mx-auto px-4 pt-4 pb-2 space-y-2">
                  {!masterclassInfo.data?.metaData?.userPurchasedBootcamp ? (
                    <SegmentedButtons
                      value={''}
                      onValueChange={async value => {
                        setLoading(true);
                        const user = await AsyncStorage.getItem('user').then(
                          user => JSON.parse(user || '{}')?.data,
                        );
                        mixpanel.track('payment_initiate', {
                          app: 'bootcamp purchase',
                          user: user,
                          bootcampId: value,
                          amount:
                            masterclassInfo?.data?.bootcamp?.id === value
                              ? masterclassInfo?.data?.bootcamp?.discountedPrice
                              : masterclassInfo?.data?.bootcamp?.bundleBootcamp
                                  ?.discountedPrice,
                          source: 'liveclass',
                          bootcampName:
                            masterclassInfo?.data?.bootcamp?.id === value
                              ? masterclassInfo?.data?.bootcamp?.title
                              : masterclassInfo?.data?.bootcamp?.bundleBootcamp
                                  ?.title,
                        });
                        RazorpayInit(
                          {
                            bootcampId: value,
                            amount:
                              masterclassInfo?.data?.bootcamp?.id === value
                                ? masterclassInfo?.data?.bootcamp
                                    ?.discountedPrice
                                : masterclassInfo?.data?.bootcamp
                                    ?.bundleBootcamp?.discountedPrice,
                            others: {
                              app: 'bootcamp purchase',
                              source: 'liveclass',
                              bootcampName:
                                masterclassInfo?.data?.bootcamp?.id === value
                                  ? masterclassInfo?.data?.bootcamp?.title
                                  : masterclassInfo?.data?.bootcamp
                                      ?.bundleBootcamp?.title,
                            },
                          },
                          null,
                          () => {
                            mutate();
                            setLoading(false);
                          },
                        );
                      }}
                      style={{
                        backgroundColor: '#2C2C8C',
                        borderRadius: 20,
                      }}
                      buttons={buttons}
                    />
                  ) : (
                    <Button
                      mode="contained"
                      className="w-full rounded-xl bg-green-500">
                      <Text className="font-bold text-xl text-white">
                        🎉 You have enrolled 🎉
                      </Text>
                    </Button>
                  )}
                  {/* <Text className="text-black">REMAINING SLOTS: 10</Text> */}
                </View>
              )}
              {!showOptions && (
                <View
                  style={{
                    zIndex: 1000,
                  }}
                  className="flex-row items-center mx-4 -my-1">
                  <Text className="text-white">Send message to</Text>
                  <Menu
                    visible={expanded}
                    onDismiss={() => setExpaned(false)}
                    contentStyle={{
                      width: 200,
                      maxHeight: 200,
                      backgroundColor: 'white',
                    }}
                    // @ts-ignore
                    className="-mt-8"
                    anchor={
                      <Button
                        mode="text"
                        compact
                        className="p-0"
                        contentStyle={{
                          flexDirection: 'row-reverse',
                        }}
                        onPress={() => setExpaned(true)}
                        icon={() => (
                          <ADIcon name="down" size={14} color="black" />
                        )}>
                        <Text className="text-red-500 m-0">
                          {messageRecipient == 'public' ? 'Everyone' : 'Admins'}
                        </Text>
                      </Button>
                    }>
                    <Menu.Item
                      titleStyle={{
                        color: 'black',
                      }}
                      leadingIcon={() => (
                        <Icon name={'account-group'} size={24} color="black" />
                      )}
                      onPress={() => {
                        setMessageRecipient('public');
                        setExpaned(false);
                      }}
                      title="Everyone"
                    />
                    <Menu.Item
                      titleStyle={{
                        color: 'black',
                      }}
                      leadingIcon={() => (
                        <Icon name={'account-star'} size={24} color="black" />
                      )}
                      onPress={() => {
                        setMessageRecipient('admin');
                        setExpaned(false);
                      }}
                      title="Admins"
                    />
                  </Menu>
                </View>
              )}
              <View
                style={{
                  width: w(102),
                  marginHorizontal: -4,
                  marginBottom: -4,
                }}
                className={`flex-row items-center justify-center p-1 rounded-b bg-black`}>
                {showOptions && (
                  <>
                    {isMuteButtonVisible && (
                      <Button
                        onPress={async () => {
                          const user = await AsyncStorage.getItem('user').then(
                            user => JSON.parse(user!)?.data,
                          );
                          mixpanelBtnClick({
                            btnType:
                              'mic_' + isTrackEnabled(microphonePublication)
                                ? 'off'
                                : 'on',
                            app: masterclassInfo?.data?.masterclass?.title,
                            user: user,
                          });
                          room.localParticipant.setMicrophoneEnabled(
                            !isTrackEnabled(microphonePublication),
                          );
                        }}
                        labelStyle={{
                          color: 'white',
                        }}
                        icon={() => (
                          <Icon
                            name={
                              isTrackEnabled(microphonePublication)
                                ? 'microphone'
                                : 'microphone-off'
                            }
                            size={24}
                            color="white"
                          />
                        )}>
                        {isTrackEnabled(microphonePublication)
                          ? 'Mute'
                          : 'Unmute'}
                      </Button>
                    )}
                    <Button
                      onPress={async () => {
                        const user = await AsyncStorage.getItem('user').then(
                          user => JSON.parse(user || '{}')?.data,
                        );
                        mixpanelBtnClick({
                          btnType:
                            'cam_' + isTrackEnabled(cameraPublication)
                              ? 'off'
                              : 'on',
                          app: masterclassInfo?.data?.masterclass?.title,
                          user: user,
                        });
                        room.localParticipant.setCameraEnabled(
                          !isTrackEnabled(cameraPublication),
                        );
                      }}
                      labelStyle={{
                        color: 'white',
                      }}
                      icon={() => (
                        <Icon
                          name={
                            isTrackEnabled(cameraPublication)
                              ? 'video-outline'
                              : 'video-off-outline'
                          }
                          size={24}
                          color="white"
                        />
                      )}>
                      {isTrackEnabled(cameraPublication)
                        ? 'Stop Video'
                        : 'Start Video'}
                    </Button>
                    <Button
                      onPress={async () => {
                        const user = await AsyncStorage.getItem('user').then(
                          user => JSON.parse(user || '{}')?.data,
                        );
                        mixpanelBtnClick({
                          btnType: 'chat_open',
                          app: masterclassInfo?.data?.masterclass?.title,
                          user: user,
                        });
                        setShowOptions(false);
                        setTimeout(() => {
                          localInputRef?.current?.focus();
                        }, 10);
                      }}
                      labelStyle={{
                        color: 'white',
                      }}
                      icon={() => (
                        <Icon name={'chat'} size={24} color="white" />
                      )}>
                      Chat
                    </Button>
                    {messageLoading ? (
                      <ActivityIndicator
                        style={{
                          height: h(6),
                          width: h(6),
                        }}
                      />
                    ) : (
                      <IconButton
                        onPress={sendLike}
                        icon={() => (
                          <ADIcon size={24} name="like1" color="#FFCA28" />
                        )}
                      />
                    )}
                  </>
                )}
                {!showOptions && (
                  <>
                    <TextInput
                      onSubmitEditing={sendMessage}
                      onBlur={() => setShowOptions(true)}
                      ref={(ref: any) => {
                        localInputRef && (localInputRef.current = ref as any);
                      }}
                      value={message}
                      onChangeText={setMessage}
                      className="flex-1 outline-none border-none bg-transparent"
                      contentStyle={{
                        color: 'white',
                      }}
                      placeholder={`Write a message for ${
                        messageRecipient == 'public' ? 'everyone' : 'admins'
                      }...`}
                    />
                    <View
                      className={
                        'rounded-xl mx-2 items-center justify-center w-10 h-10 ' +
                        (message.length > 0
                          ? 'bg-red-600/90'
                          : 'bg-transparent')
                      }>
                      {messageLoading ? (
                        <ActivityIndicator />
                      ) : (
                        <IconButton
                          onPress={() => {
                            sendMessage();
                            setIsScrolling(false);
                            setUnreadMessages(unreadMessages + 1);
                          }}
                          icon={() => (
                            <Icon name={'send'} size={18} color="white" />
                          )}
                        />
                      )}
                    </View>
                  </>
                )}
              </View>
            </View>
            <ExitDialog
              exitFn={async () => {
                const user = await AsyncStorage.getItem('user').then(
                  user => JSON.parse(user || '{}')?.data,
                );
                mixpanelBtnClick({
                  btnType: 'leave_meeting',
                  app: masterclassInfo?.data?.masterclass?.title,
                  user: user,
                });
                room.disconnect();
                analytics().logEvent('leave_meeting', {
                  title: masterclassInfo?.data?.masterclass?.title,
                });
                setDialogVisible(false);
                navigation.pop();
              }}
              visible={dialogVisible}
              setVisible={setDialogVisible}
              title="Leave Meeting"
              content="Are you sure you want to leave the meeting?"
            />
          </>
        </TouchableWithoutFeedback>
      </View>
    </PIPCard>
  );
}