프론트엔드/React

axios 사용한 리액트 컴포넌트

고줭 2021. 7. 12. 01:50

안녕하세요 오랜만에 글 쓰네요.

Spring Boot + React로 작은 프로젝트를 진행중에 있는데 얼마전에 기본적인 프론트는 끝냈다고 생각하고 백쪽을 다듬으려고 하던찰나에 useEffect가 무한루프에 빠졌다는 사실을 알아채리고 조금씩 수정하려다가 다시 다 엎고 시작했습니다.

우선 전에 썻던 코드를 보시죠

import React, {useEffect, useState} from "react";
import Header from "./Header";
import Article from "./Article";
import {getFetch} from "../util/getFetch";
import {postFetch} from "../util/postFetch";

export default function MainComponent(){

    const [hintListSize, setHintListSize] = useState();

    const [merchant, setMerchant] = useState('MRC001');
    const [themeCode, setThemeCode] = useState('THM001');
    const [message1, setMessage1] = useState();
    const [message2, setMessage2] = useState();

    const [themeList, setThemeList] = useState([]);
    const [hintList, setHintList] = useState([]);

    const registerData = {
        message1: message1,
        message2: message2,
        themeCode: themeCode,
        merchant: merchant
    };

    const registerHint = async () => {
        await postFetch('/registerHint', registerData);
    }

    const getThemeList = async () => {
        const data = await getFetch(`/theme/list?merchantCode=${merchant}`);
        setThemeList(data);
    }

    const handleMessage1 = (message1) => {
        setMessage1(message1);
    }

    const handleMessage2 = (message2) => {
        setMessage2(message2);
    }

    const handleMerchantState = (merchant) => {
        setMerchant(merchant);
    }

    const handleThemeCodeState = (themeCode) => {
        setThemeCode(themeCode);
    }

    const getHintList = async () => {
        const data = await getFetch(`/getHint?merchantCode=${merchant}&themeCode=${themeCode}`);
        setHintList(data);
        setHintListSize(data.length+1);
    }

    useEffect(() => {
        getThemeList();
    },[setThemeList]);

    useEffect(() => {
        getHintList();
    },[hintList]);

    return(
      <div>
          <Header handleMerchantState={handleMerchantState} merchantState={ merchant }
                  themeCodeState={ handleThemeCodeState } themeListState={ themeList }
                  hintListSize={hintListSize} handleMessage1={handleMessage1}
                  handleMessage2={handleMessage2} registerHint={registerHint}/>
          <Article hintListSize={hintListSize} hintState={hintList}/>
      </div>
    );
}

 

전체 React코드는 아닙니다.
우선 통신은 fetch를 사용했습니다 getFetch와 postFetch를 각각 유틸화해서 데이터를 가져오고 가져온데이터를 바탕으로 themeList, hintList를 가져오게끔 했는데 어디가 문제였는지 무한루프에서 나오지 못하더라구요.. 백도 잘 모르지만 프론트는 완전 잼병인데다가 스프링부트도 처음, 리액트도 처음(사실상 React-bootstrap) 이라서 엎어버렸습니다.

개선된 코드를 보시죠

import React, {useEffect, useState} from "react";
import Header from "./Header";
import Article from "./Article";
import axios from "axios";

export default function MainComponent() {

    const [hintListSize, setHintListSize] = useState();

    const [merchantCode, setMerchantCode] = useState('MRC001');
    const [themeCode, setThemeCode] = useState('THM001');
    const [message1, setMessage1] = useState();
    const [message2, setMessage2] = useState();

    const [merchantList, setMerchantList] = useState([]);
    const [themeList, setThemeList] = useState([]);
    const [hintList, setHintList] = useState([]);

    // post 메소드 실행시 힌트리스트 갱신용
    const [isModified, setIsModified] = useState(true);

    const handleMerchantCode = (e) => {
        setMerchantCode(e.target.value);
    }

    const handleThemeCode = (e) => {
        setThemeCode(e.target.value);
    }

    const handleMessage1 = (e) => {
        setMessage1(e.target.value);
    }

    const handleMessage2 = (e) => {
        setMessage2(e.target.value);
    }

    const deleteHint = (e) => {
        let isDelete = window.confirm('정말 삭제하시겠습니까?');
        let object = {
            seq: e.target.id
        }
        if(isDelete){
            axios.post('/deleteHint', object)
                .then(() => setIsModified(!isModified))
                .catch(console.log);
        }
    }

    const registerHint = () => {
        const registerData = {
            message1: message1,
            message2: message2,
            themeCode: themeCode,
            merchant: merchantCode
        };
        axios.post(`/registerHint`, registerData)
            .then(() => setIsModified(!isModified))
            .catch(console.log);
    }

    useEffect(() => {
        axios.get(`/merchant/list`)
            .then(res => setMerchantList(res.data))
            .catch(console.log);

    }, []);

    useEffect(() => {
        axios.get(`/theme/list?merchantCode=${merchantCode}`)
            .then(res => setThemeList(res.data))
            .catch(console.log);

    }, [merchantCode]);

    useEffect(() => {
        axios.get(`/getHint?merchantCode=${merchantCode}&themeCode=${themeCode}`)
            .then(res => {
                setHintList(res.data);
                setHintListSize(res.data.length + 1);
            })
            .catch(console.log);

    }, [merchantCode, themeCode, isModified])

    return (
        <div>
            <Header merchantList={merchantList} handleMerchantCode={handleMerchantCode}
                    themeList={themeList} handleThemeCode={handleThemeCode} hintListSize={hintListSize}
                    handleMessage1={handleMessage1} handleMessage2={handleMessage2} registerHint={registerHint}
                    />
            <Article hintList={hintList} deleteHint={deleteHint}/>
        </div>
    );
}

위와 크게 다른점이 있다면 fetch대신 axios를 사용했습니다. 이유는 딱히 없습니다. 또한 유틸화하지않고 그대로 가져다가 썼는데 리액트에서는 어떻게 코드를 정리하고 모듈화하고 상태값을 전달하는지 아예몰라서 최대한 상위컴포넌트에서 통신하고 하위로 props를 보내는 식으로만 코드를 짰습니다. 

또한 post 통신을 할때는 통신이 됐는지 안됐는지를 판별하기위해 isModified 변수를 선언해서 값을 바꿔주는 식으로 썻습니다. 아마 이게 개선전 무한루프에 빠졌던 이유가 아닐까싶습니다. 

어쨌든 지금은 정상작동하고 짜잘하게 지저분했던 하위컴포넌트도 정리했고 꽤 만족합니다.

앞으로 할 일은 로그인기능 입니다.
세세하게 얘기하자면 React에서도 router를 사용해서 화면 분기처리를 해줘야하고 SpringBoot쪽에서도 로그인 정보가 맞는지 아닌지 MemberVO는 어떻게 설정할것인지 등등 할게 많네요..

https://github.com/kojoo112/XCAPE-HINT

 

kojoo112/XCAPE-HINT

Contribute to kojoo112/XCAPE-HINT development by creating an account on GitHub.

github.com

혹시나 제 프로젝트가 궁금하시다면 여기서 확인하시면 되겠습니다.