Firebase - online상태 나타내기(7)

online, offline 상태 나타내기

유저가 온라인 상태인지 오프라인 상태인지 나타내기 위해서는 User의 connection 상태를 알 수 있어야 한다.

channel6 Offline
channel7 Online

Connection state

firebase의 database는 유저가 online상태면 .info/connected 라는 특수한 refvalue를 추가한다. 이를 코드로 표현하면 다음과 같다.

const connectionRef = firebase.database().ref(".info/connected");

connectionRef.on("value", (snap) => {
  if (snap.val()) {
    // online
    // 유저 온라인 상태 저장
  } else {
    // offline
  }
});

presence 저장하기

유저의 connection상태를 저장해야 해당 데이터를 가져와 화면에 connection상태를 보여줄 수 있을 것이다. 따라서 connection상태를 저장하는 presence collection을 구성한다.

const presenceRef = firebase.database().ref("presence");

유저의 커넥션 상태가 online인 경우, presence에 해당 유저의 키를 저장한다. 그리고 offline상태면 유저의 키를 삭제한다.

// 컴포넌트가 마운트하면 presence에 유저의 커넥션 상태가 저장된다.
useEffect(() => {
  connectionRef.on("value", (snap) => {
    if (snap.val()) {
      // presence 밑에 현재 유저 아이디 ref를 형성한다.
      const ref = presenceRef.child(currentUser.id);
      ref.set(true); // online 상태 => true

      // Disconnect시, 데이터를 remove 한다.
      ref.onDisconnect().remove((err) => {
        if (err) {
          // remove error
          console.error(err);
        }
      });
    } else {
      // offline
    }
  });
}, []);
channel8 로그인 이전
channel9 로그인 이후 presence에 값이 추가되는 것을 볼 수 있다.

커넥션 상태 화면에 표현하기

presence 가져오기

presenceRef를 통해서 값을 가져올 수 있다.

const [presenceList, setPresenceList] = useState([]);
useEffect(() => {
  let loaded = [];
  presenceRef.on("child_added", (snap) => {
    if (currentUser.id !== snap.key) {
      loaded.push(snap.key); // 다른 유저의 키가 담기게 된다.
      setPresenceList([...loaded]);
    }
  });

  presenceRef.on("child_remvoved", (snap) => {
    let loaded = [];
    if (currentUser.id !== snap.key) {
      loaded.push(snap.key); // 다른 유저의 키가 담기게 된다.
      setPresenceList([...loaded]);
    }
  });
}, []);

이제 activeUsers에는 현재 접속해 있는 유저의 키가 담기게 된다. 이제 이 키를 이용하여 어떤 유저가 접속해있는지 화면에 표시할 수 있다.

presence 표현하기

데이터베이스에서 users를 가져온 다음에 user에 status라는 새로운 프로퍼티를 만들고 presence에 따라서 online 또는 offline 값을 부여해준다.

const [users, setUsers] = useState([]);
const usersRef = firebase.database().ref("users");
useEffect(() => {
  let loaded = [];
  usersRef.child("child_added", (snap) => {
    if (currentUser.id !== snap.key) {
      let user = snap.val();
      user["id"] = snap.key;
      if (presenceList && presenceList.includes(user.id)) {
        user["status"] = "online";
      } else {
        user["status"] = "offline";
      }
      loaded.push(user);
      setUsers([...loaded]);
    }
  });
}, []);

// user.status로 connection상태를 조회할 수 있다.

JSX코드에서 다음과 같이 스타일링할 수 있다.

{
  users.map((user) => (
    <Menu.Item>
      {user.name}
      <Icon name="circle" color={user.status === "online" ? `green` : "red"} />
    </Menu.Item>
  ));
}

further readings