본문 바로가기
  • 삽질하는 자의 블로그
메인-프로젝트/React - Do-Health 프로젝트

17. [기능 업데이트] 달력의 delete 기능 업데이트. 마무리는 무슨 ...

by 이게뭐당가 2023. 1. 5.

들어가기 전에, 이번에 클래스에 대해 배운 것들 총정리

<예시 : 클래스의 상향식 props 사용>

    1) 상위컴포넌트(App.tsx) 로 부터 하위 컴포넌트(클래스형) 으로 함수를 넘긴다.

    2) 클래스 컴포넌트에서는, interface Props {} 로, 넘겨받을 함수의 타입을 지정한다.

    3) 클래스의 interface xxxAppState {} 를 통해, State 로 사용할 타입을 정의한다.

    3) 클래스의 메인클래스( export default class Calendar extends ...으로 시작하는) 
        안의 state: ... = {} 를 통해, state를 초기화한다.

    4) 클래스의 this.setState() 를 통해, state 에 값을 넣는다. 이때, render 보단 밖에서, 함수를 정의하고, 함수를 사용하는 형태로 state 를 넣는다.
    5) 클래스의 render(){} 안쪽에서, App.tsx 로부터 넘겨받은 함수를 사용한다. state 의 값과 함께

        * 넘겨받은 props 를 사용하려면, 반드시, render 함수 안에서 사용해야하고(컴포넌트함수처럼)
        * 클래스에서는 값을 사용하려면, useState 처럼, state 를 반드시 사용해야한다.

 

배운 것 예시

interface DemoAppState {            // state 로 사용할 것의 타입들
    weekendsVisible: boolean;
    currentEvents: EventApi[];
    textid: string; 			//  state의 type 을 등록
    email: string; 				//  state의 type 을 등록
    useEmail: string;
}

interface Props {                   // Props 로 넘겨받을 값들의 타입들
    calendarData: { title: string; start: string; email: string }[];
    getOut: () => void;
    isLogedIn: { idToken: string; email: string };
    dataFromCalendarForDelete: (id: string, email: string) => void;
}

export default class Calendar extends React.Component<Props, {}, DemoAppState> {    // state 와, Props 등, 타입을 전부 넣는다.
    state: DemoAppState = {     // state 의 초기화
        weekendsVisible: true,
        currentEvents: [],
        textid: "",                         // state 사용을 위한 초기화
        email: "",                          // state 사용을 위한 초기화
        useEmail: this.props.isLogedIn.email,
    };
    
    render() {
        const calendarData = this.props.calendarData;
        const getOut = this.props.getOut;			// this.props 로, props 로 넘어 온 값 사용
        const isLogedIn = this.props.isLogedIn;
        const dataFromCalendarForDelete = this.props.dataFromCalendarForDelete;
        const { textid, email, useEmail } = this.state;		// this.state 로, state 값 사용

        if (!isLogedIn.email) {
        	getOut();
        }

        if (textid) {
        	dataFromCalendarForDelete(textid, email); // App.js 로 넘긴다.
        }

 

본격적으로 캘린더에서, 값 삭제(DB 에서 삭제) 만들기 시작

 

1. FIREBASE 의 DELETE  METHOD

"중첩된 아이디의 주소로 접근해서 DELETE method를 사용하기만 하면 된다."
** 그러므로, "SDFC23dfgCD" 따위의 "Firebase DB가 만드는 자동 생성 id" 도, fetch 를 할때 가져와야 하겠다.

 

2. 캘린더 내에서, event 의 값을 Delete 하려 했을때, 그 정보 가져오기

: console.log(clickInfo.event) 에 접근해서, 안에 있는 데이터를 알아보았다.
결과적으로, 필요한 값을 뺀 것이 아래에 있는 두개의 것들이다.

    handleEventClick = (clickInfo: EventClickArg) => {
        if (
        	window.confirm(		 // window 를 앞에 붙였다.
            	`Are you sure you want to delete the event '${clickInfo.event.title}'`
        )
        ) {
        clickInfo.event.remove();
        
        console.log(clickInfo.event._def.publicId);         // 지정했을때 Id (1,2...하면서 올라가는)
        console.log(clickInfo.event.extendedProps.email);   // 작성자 email
        
        }
    };

 

 

3. 기존에, fetch 를 하고, Data 를 Refine 할때, DB에서 오는 자동생성ID 는 버렸다. 하지만 이젠 필요하다.

< store / calendar-action.tsx >

    export const sendRequest = () => {
        return async (dispatch: Dispatch) => {      // 타입은 Dispatch 이다.         

            const fetchData = async () => {            // 비동기 함수 만들어서

                const response = await fetch(
                    "https://do-health-project-default-rtdb.firebaseio.com/user/calendar.json"
                );
                const responseData = await response.json();

                const refineData = [];                  // 파이어 베이스에서 데이터 것 refine

                for (const key in responseData) {
                    refineData.push({
                        firebaseid:key,                     // 추가적으로 firebaseid 를 가져온다. (삭제용)
                        id: createEventId(),
                        title: responseData[key].title,
                        start: responseData[key].start,
                        email: responseData[key].email,
                    });
                }

 

4. 클래스 내에서, State 를 사용하기 위해, state의 타입을 지정하고 초기화하기

import { addCalendarToDb } from "../helper/calendar-add-to-DB"; // 내가 넣은 DB에 넣을 함수

interface DemoAppState {
    weekendsVisible: boolean;
    currentEvents: EventApi[];
    textid: string;             // 미리 state의 type 을 등록
    email: string;              // 미리 state의 type 을 등록
}

interface Props {
    calendarData: { title: string; start: string; email: string }[];
    getOut: () => void;
    isLogedIn: string;
    dataFromCalendarForDelete: (id: string, email: string) => void;
}

export default class Calendar extends React.Component<Props, {}, DemoAppState> {
    state: DemoAppState = {
        weekendsVisible: true,
        currentEvents: [],
        textid: "",             // state 사용을 위한 초기화
        email: "",              // state 사용을 위한 초기화
};

    render() {
        const calendarData = this.props.calendarData;

 

5. 캘린더 클래스 내의 [기존 Delete 함수] 에, State 가 업데이트 되도록, 코드 넣기

< 캘린더의 이벤트 클릭 핸들러에, state를 업데이트 하게 한다.>

    handleEventClick = (clickInfo: EventClickArg) => {
        if (
            window.confirm(
                `Are you sure you want to delete the event '${clickInfo.event.title}'`
        )
        ) {
        clickInfo.event.remove();
        
        this.setState({                             // delete 를 하면, State를 업데이트한다.
            textid: clickInfo.event._def.publicId,
            email: clickInfo.event.extendedProps.email,
        });
        }
    };

 

6. 그렇게 업데이트 된, 캘린더의 State 를 App.tsx 온 함수에 넣어, [상향식 props 완성하기]

<캘린더의 업데이트된 State와, App.tsx 에서 온 상향식 props 를 위한 함수로, App.tsx 로 값을 넘긴다.>

interface Props {
    calendarData: { title: string; start: string; email: string }[];
    getOut: () => void;
    isLogedIn: string;
    dataFromCalendarForDelete: (id: string, email: string) => void;         // App.tsx 에서 상향식 props 를 위해 함수를 넘겨준다.
}

export default class Calendar extends React.Component<Props, {}, DemoAppState> {
    state: DemoAppState = {
    weekendsVisible: true,
    currentEvents: [],
    textid: "",                 // state 사용을 위한 초기화
    email: "",                  // state 사용을 위한 초기화
};

    render() {
        const calendarData = this.props.calendarData;
        const getOut = this.props.getOut;
        const isLogedIn = this.props.isLogedIn;
        const dataFromCalendarForDelete = this.props.dataFromCalendarForDelete;
        const { textid, email } = this.state;        // delete 버튼을 누르면, state 를 받아온다.

        if (!isLogedIn) {
            getOut();
        }

        if (textid) {
            dataFromCalendarForDelete(textid, email);   // App.tsx 로 넘긴다. (App.tsx 에서 넘어온 상향식 Props 를 위한 함수)
        }

        return (
        <div className="demo-app">
            <div className="demo-app-main">

 

[여기서잠깐. render 안에서, State 의 값을 변경하는 것은 불가능하단다. 난 모르고 열심히 오류를 냈다.]

 

 

7. App.tsx 에서 캘린더로부터 온 값을 가지고, firebaseid 알아내고, 삭제하기

<helper 함수를 생성한다>

    export const removeCalendarToDb = async (firebaseid: string) => {
        await fetch(
            `https://do-health-project-default-rtdb.firebaseio.com/user/calendar/${firebaseid}.json`,
            {
                method: "DELETE",
            }
        );
    };

    ==> firebase는 "id 가 곧, 주소"이기 때문에, 주소의 끝단에, id 를 붙여놓고, Delete method 만 사용하면 된다.

<App.tsx 에서, 캘린더로부터 넘겨받은 값을 가지고, Data 를 뒤져, 맞는 firebaseId를 찾아낸다.>


        const dataFromCalendarForDelete = (id: string, email: string) => {     // 캘린더 안의 delete 하기 위한 값 넘겨받기, 삭제하기
            const selectedFirebaseData = calendarData.find(
                (item) => item.id === id && item.email === email
            );

            if (selectedFirebaseData !== undefined) {
                const selectedFirebaseId = selectedFirebaseData.firebaseid;

                removeCalendarToDb(selectedFirebaseId);
            }
        };

** store 의 Slice 에서, 새 타입을 지정하는 것을 잊지 말자. firebaseid:string이라던가... (기존에는 등록해 놓지 않은 타입이 많다.)

 

댓글