Iceconnectionstate is not updated

import React from 'react';
import { useEffect, useRef, useState } from 'react';
import { SafeAreaView, StatusBar, StyleSheet, View } from 'react-native';
import {
  RTCPeerConnection,
  RTCIceCandidate,
  RTCSessionDescription,
  mediaDevices,
  MediaStream,
} from 'react-native-webrtc';
import GettingCall from './GettingCall';
import VideoButton from './VideoButton';
import Video from './Video';
import firestore from '@react-native-firebase/firestore';

const peerConstraints = {
  iceServers: [
    { urls: 'stun:stun.l.google.com:19302' },
    { urls: 'stun:stun1.l.google.com:19302' },
    { urls: 'stun:stun2.l.google.com:19302' },
    { urls: 'stun:stun3.l.google.com:19302' },
    { urls: 'stun:stun4.l.google.com:19302' },
    {
      urls: 'turn:turn.bistri.com:80',
      credential: 'homeo',
      username: 'homeo',
    },
  ],
};

function VideoInitial() {
  let localStream = useRef<MediaStream>();
  let remoteStream = useRef<MediaStream>();
  const [local, setLocal] = useState<string | null>(null);
  const [remote, setRemote] = useState<string | null>(null);
  const [gettingCall, setGettingCall] = useState(false);
  const connecting = useRef(false);
  let pc = useRef<RTCPeerConnection>();

  // Global state

  useEffect(() => {
    const cRef = firestore().collection('meet').doc('chatId');

    const subscribe = cRef.onSnapshot((snapshot) => {
      const data = snapshot.data();
      if (pc.current && !pc.current.remoteDescription && data && data.answer) {
        pc.current.setRemoteDescription(new RTCSessionDescription(data.answer));
      }
      if (data && data.offer && !connecting.current) {
        setGettingCall(true);
      }
    });

    const subscribeDelete = cRef.collection('callee').onSnapshot((snapshot) => {
      snapshot.docChanges().forEach((change) => {
        if (change.type === 'removed') {
          hangup();
        }
      });
    });
    return () => {
      subscribe();
      subscribeDelete();
    };
  }, []);

  async function setupWebrtc() {
    pc.current = new RTCPeerConnection(peerConstraints);

    localStream.current = await getStream();

    if (localStream.current) {
      setLocal(localStream.current.toURL());

      localStream.current.getTracks().forEach((track) => {
        localStream.current && pc.current?.addTrack(track, localStream.current);
      });
    }

    remoteStream.current = new MediaStream(undefined);
    pc.current.ontrack = (event: any) => {
      if (remoteStream.current) {
        remoteStream.current?.addTrack(event.track);
      }
    };
  }

  async function create() {
    console.log('calling');
    connecting.current = true;

    await setupWebrtc();

    const cRef = firestore().collection('meet').doc('chatId');

    collectIceCandidates(cRef, 'caller', 'callee');

    if (pc.current) {
      console.log('create');
      try {
        let sessionConstraints = {
          mandatory: {
            OfferToReceiveAudio: true,
            OfferToReceiveVideo: true,
          },
        };
        const offerDescription = await pc.current.createOffer(
          sessionConstraints,
        );
        await pc.current.setLocalDescription(offerDescription);
        const cWithOffer = {
          offer: {
            type: offerDescription.type,
            sdp: offerDescription.sdp,
          },
        };

        await cRef.set(cWithOffer);
      } catch (error) {
        console.log('error', error);
      }
    }
  }

  const join = async () => {
    console.log('Joining the call');
    connecting.current = true;
    setGettingCall(false);

    const cRef = firestore().collection('meet').doc('chatId');
    const offer = (await cRef.get()).data()?.offer;

    if (offer) {
      await setupWebrtc();

      collectIceCandidates(cRef, 'callee', 'caller');

      if (pc.current) {
        await pc.current.setRemoteDescription(new RTCSessionDescription(offer));

        const answer = await pc.current.createAnswer();
        await pc.current.setLocalDescription(answer);
        const cWithAnswer = {
          answer: {
            type: answer.type,
            sdp: answer.sdp,
          },
        };
        await cRef.update(cWithAnswer);
      }
    }
  };

  async function hangup() {
    console.log('hangup');
    setGettingCall(false);
    connecting.current = false;
    streamCleanUp();
    firebaseCleanUp();
    if (pc.current) {
      pc.current.close();
    }
  }

  async function getStream() {
    let isVoiceOnly = false;
    let mediaConstraints = {
      audio: true,
      video: {
        frameRate: 30,
        facingMode: 'user',
      },
    };
    try {
      const mediaStream = await mediaDevices.getUserMedia(mediaConstraints);

      if (isVoiceOnly) {
        let videoTrack = mediaStream.getVideoTracks()[0];
        videoTrack.enabled = false;
      }

      return mediaStream;
    } catch (err) {
      console.log('err', err);
    }
  }

  async function streamCleanUp() {
    console.log('streamCleanUp');
    if (localStream.current) {
      localStream.current.getTracks().forEach((t) => t.stop());
      localStream.current.release();
    }
    setLocal(null);
    setRemote(null);
  }

  async function firebaseCleanUp() {
    console.log('firebaseCleanUp');
    const cRef = firestore().collection('meet').doc('chatId');
    if (cRef) {
      const callee = await cRef.collection('callee').get();
      callee.forEach(async (candidate) => {
        await candidate.ref.delete();
      });
      const caller = await cRef.collection('caller').get();
      caller.forEach(async (candidate) => {
        await candidate.ref.delete();
      });
      await cRef.delete();
    }
  }

  function collectIceCandidates(cRef, localName, remoteName) {
    console.log('localName', localName);
    const candidateCollection = cRef.collection(localName);

    if (pc.current) {
      pc.current.onicecandidate = (event: any) => {
        if (event.candidate && pc.current?.remoteDescription === null) {
          candidateCollection.add(event.candidate.toJSON());
        }
      };
      cRef.collection(remoteName).onSnapshot((snapshot) => {
        snapshot.docChanges().forEach((change) => {
          if (change.type === 'added') {
            const candidate = new RTCIceCandidate(change.doc.data());
            pc.current?.addIceCandidate(candidate);
          }
        });
      });
      pc.current.oniceconnectionstatechange = () => {
        if (
          pc.current?.iceConnectionState === 'failed' ||
          pc.current?.iceConnectionState === 'disconnected' ||
          pc.current?.iceConnectionState === 'closed'
        ) {
          console.log('failed');
        } else if (pc.current?.iceConnectionState === 'checking') {
          console.log('checking');
        } else {
          console.log('success');
          remoteStream.current && setRemote(remoteStream.current?.toURL());
        }
      };
    }
  }

  if (gettingCall) {
    console.log('gettingCall');
    return <GettingCall hangup={hangup} join={join} />;
  }

  if (local) {
    console.log('localStream');
    return <Video hangup={hangup} local={local} remote={remote} />;
  }

  return (
    <SafeAreaView style={{ flex: 1 }}>
      <StatusBar barStyle="dark-content" />
      <View style={styles.container}>
        <VideoButton iconName="video" backgroundColor="grey" onPress={create} />
      </View>
    </SafeAreaView>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});

export default VideoInitial;

I am working on simple webrtc and tried this code, but iceconnectionstate is not updated from checking to completed, so can’t show remote video stream.
Any help?

Do both peers send / receive ice candidates? I’m not fully sure about this condition:
if (event.candidate && pc.current?.remoteDescription === null)
…since now whenever you have set the remote description, you are not communicating those to another peer.

would it work better with just
if (event.candidate)