Firebase - Channel 추가하기(3)

채널 스키마 구성하기

채널 기능

여기서 채널은 쉽게 말해서 채팅룸을 의미한다. 채널을 만들면 유저는 채널 내에서 채팅을 할 수 있다.

channel2

채널 스키마(Schema) 설정

채널을 저장하기 위해 먼저 스키마를 설정한다. 채널 Doocument는 채널이름, 채널설명, 채널 개설 날짜 등 여러 가지 데이터를 가질 수 있다. 다음과 같이 채널 스키마를 구성한다.

channel1

채널 추가하는 코드 작성하기

채널 추가

채널을 추가하기 위한 데이터로는 채널 이름과 채널에 대한 설명이 필요하다. 사용자의 입력(Input)이 필요하므로 유저 인터페이스로는 Form 컴포넌트가 필요하다. Form컴포넌트가 있다고 가정하고, 채널을 추가하는 코드를 먼저 작성한다. 데이터베이스에 채널을 추가하는 것이기 때문에 channels에 대한 Reference가 필요하다. 다음과 같이 채널 ref를 변수로 관리한다. (ref와 관련된 코드를 따로 파일로 관리할 수도, Container 컴포넌트에 작성할 수도 있다.)

const channelRef = firebase.database().ref("channels");

firebase의 Realtime database에 데이터를 Write하기 위해서 set() 또는 update() 메소드를 사용한다. set()Promise를 반환하기 때문에 async함수를 정의하거나 then()을 사용한다.


export const addChannel(channel, user) = () => {
    const key = channelsRef.push().key; // generate unique id
    const newChannel = {
        id: key,
        name: channel.name,
        description: channel.description,
        createdBy: {
            name: user.name,
            avatar: user.photoURL,
        }
    }
    channelRef.child(key).set(newChannel).then(() => {
        // Success

    }).catch((err) => {
        // Fail


    })
}

채널 가져오기

채널을 추가하면 바로 화면에 추가한 채널이 나타나야 한다. 데이터베이스에 저장된 채널이 실시간으로 화면에 나타나기 위해서는 데이터베이스에 있는 channels를 Listen하는 코드를 작성해야한다. 데이터베이스의 Reference는 Nodejs의 EvnetEmitter와 동일한 구조로 on(evnetType, callback)이라는 메소드를 제공한다. 데이터베이스와 관련된 이벤트 타입으로는 value, child_added, child_removed, child_changed, child_move이 있다. 그 중valuechild_added가 데이터가 store될 때 때마다 trigger되는데, child 포지션의 데이터를 listen하기 위해 child_added를 이용한다.

// callback함수는 DataSnapshot 이라는 객체를 인자로 전달받는다.
ref.on("child_added", (snap: firebase.database.DataSnapshot) => {
  // DataSnapshot에서 value를 추출하기 위해선 val() 메소드를 사용한다.
  const value = snap.val();
});

useEffect를 이용하여 렌더링 이후 child_added 리스너를 등록한다.

// channel를 UI에 렌더링하기 위해 useState훅을 사용한다.
const [channels, setChannels] = useState([]);
useEffect(() => {
  let loaded = [];
  // 처음 리스너가 등록된 이후 최초 한번 실행하고 이후 child_added이벤트가 발생할때마다 실행한다.
  channelsRef.on("child_added", (snap) => {
    loaded.push(snap.val());
    // channels state에 담는다.
    setChannels([...loaded]);
    });
  });
  // off()메소드를 이용하여 리스너를 해제한다.
  return () => channelsRef.off();
}, []);

컴포넌트가 최초 마운트하고 나면 리스너가 등록하고, 데이터베이스로부터 channels를 가져오게 된다. 가져온 channels는 state에 담기게 되고 화면에 렌더링하게 된다.

further readings