Study/React

[ReactJS/AXIOS] 백엔드 없이 로그인 구현하기 (4)

hyjang 2024. 7. 4. 01:22
728x90

지난 포스팅에서는 댓글 리스트를 불러와봤다.

그리고 댓글 작성 시 나의 정보를 댓글 데이터에 추가하기 위해 암호화한 로컬스토리지를 저장하는 작업을 했다.

 

해당 작업으로 새로고침해도 로그인을 유지할 수 있도록 true 값을 저장하는 작업도 할 수 있었다.

//Header.js 로그아웃 버튼에 추가
 secureLocalStorage.setItem("AutoLogIn", false);
 
 //LogIn.js 로그인 성공 조건문에 추가
 secureLocalStorage.setItem("AutoLogIn", true);
 
 //App.js 에 추가
   useEffect(()=>{
    const AutoLogIn = secureLocalStorage.getItem("AutoLogIn");
    setLogInCheck(AutoLogIn);
  },[])
useEffect의 의존성 배열을 비워두면 처음 렌더링시에만 실행된다.(마운트)

 


댓글 작성하기

이번엔 data.json 서버에 보낸 데이터와 로컬스토리지에 저장된 데이터를 이용하여 댓글 리스트를 추가해보자.

 

"review": [
    {
      "memName": "김철수",
      "memId": "kim1234",
      "day": "2024-05-30",
      "content": "잘 보고 갑니다.",
      "id": "6082"
    },
    {
      "memName": "홍길동",
      "memId": "hong1234",
      "day": "2024-05-20",
      "content": "항상 행복하세요.",
      "id": "5004"
    }
  ]

현재 내가 데이터 서버에 저장한 객체들이다.

 

  • memName : 이름
  • memId : 아이디
  • day : 작성 날짜
  • content : 작성 내용

이 네가지 데이터를 서버로 전송해보자

import axios from "axios";
import secureLocalStorage from "react-secure-storage";
import { useRef } from "react";
(...)

    function hondleOnClickPost(){
        if(window.confirm("등록하시겠습니까?")){
        const memInfo = secureLocalStorage.getItem("memInfo")
        axios.post('http://localhost:3001/review',{ 
            memName: memInfo[0].memName ,
            memId:  memInfo[0].memId ,
            day:"2024-06-03",
            content:  refText.current.value 
        }) 
        alert("등록되었습니다.")
        refText.current.value = ''; 
        }
    } 
    return(
        <div className="reviewPost">
                    <h2>리뷰 작성하기</h2>
                    <textarea onClick={handleOnClickCheck} ref={refText}  maxLength="300" placeholder="리뷰를 입력해주세요."  type="text" />
                    <button onClick={hondleOnClickPost}>등록</button>
         </div>
    )
}

 

댓글 내용은 useRef로 HTML DOM에 접근하여 value값을 가져왔다. 

 

 

memInfo[0].memName ?

로컬스토리지에서 특정값을 가져올 때 memInfo[0].memName처럼 적은 이유는

react-secure-storage를 사용해서인지 그냥 memInfo를 콘솔에 찍어보면

이런식으로 배열의 형태로 저장이 된다.

여기서 정보를 담고있는 매개변수가 숫자이므로 memInfo.0.memName은 사용할 수 없었다.

 

그래서 이런 저런 시도를 해본 끝에 memInfo[0].memName으로 적으면 정상적으로 값이 나오는 것을 확인했다 ..

 

아무튼 위의 코드처럼 작성을 하면 정상적으로 등록이 된다.

하지만 실시간으로 적용되지 않고 새로고침을 해야만 보인다.

 

데이터가 바뀔때마다 렌더링이 되도록 useEffect 훅을 사용해주자

 


useEffect 리액트 훅

ReviewPost 컴포넌트에서 댓글을 달면 부모 컴포넌트인 App.js로 보낸다.

그리고 그 데이터를 다시 ReivewList 컴포넌트로 보내주면 된다.

 

여기서 제일 오랜시간이 걸렸는데 axios를 사용하다보니 상황마다 객체로 전달될 때, 배열로 전달될 때가 달랐다.

그래서 item.data 또는 item 이렇게 쓰일때가 많았다 .. 

 

먼저 App.js 에서 데이터를 useFetch를 통해 얻어온다.(GET)

그리고 데이터가 추가될 때마다 렌더링하며 자식 컴포넌트에게 데이터를 전달한다.

 

//App.js
const item = useFetch('http://localhost:3001/review') ;
 const [data, setData] = useState(item);  
 function dataSave(review){
    setData(it=>[...it, review.data].sort((a,b)=>new Date(b.day) - new Date(a.day)))
  } 
  useEffect(()=>{
    setData(item.data);
    item.data?.sort((a,b)=>new Date(b.day) - new Date(a.day))  
  },[item])

먼저 useState에서 초깃값을 item으로 두고 set 함수와 state 변수를 정했다.

이렇게 되면 처음 새로고침할 때 state 변수는 빈 값이 되기때문에 useEffect에 의존성 배열을 item으로 두면서 state를 업데이트해 불러와야한다. 

컴포넌트를 페이지에 처음 렌더링할 때를 '마운트' 라고 한다.  

 

그리고 dataSave의 매개변수인 review는 ReviewPost.js에서 새로 받아올 댓글 데이터다. 

이때 review는 객체 형태로 오기 때문에 그 속에 있는 data를 불러온다. 

 

보통 어딘가에서 데이터가 추가되어 받아올 때는 set변수(it=>[...it, 새로운데이터]) 로 많이 쓰이는 것 같다.

 

//ReviewPost.js
(...)
export default function ReviewPost({LogInCheck, dataSave}){
(...)
    function HondleOnClickPost(){ 
        if(window.confirm("등록하시겠습니까?")){
        const memInfo = secureLocalStorage.getItem("memInfo")
        axios.post('http://localhost:3001/review',{ 
            memName: memInfo[0].memName ,
            memId:  memInfo[0].memId ,
            day:"2024-06-03",
            content:  refText.current.value 
        }) 
        .then(res=>{ 
            dataSave(res) 
        })
        alert("등록되었습니다.")
        refText.current.value = ''; 
        }
    }
(...)

res는 post에서 새로 추가하게 된 데이터다. 

App.js에서 dataSave의 매개변수로 res를 보내주면 dataSave안에 있던 set함수가 실행된다.

이렇게 되면 App.js에 있던 데이터 state가 업데이트 되면서 렌더링 된다. 

그럼 이 데이터state를 댓글 리스트로 보내주면 된다. 

 

//ReviewList.js

export default function ReviewList({data}){     
    return(
        <div className="reviewList">
        <ul> 
            {data?.map((it)=>(
                <li key={it.id}>
                    <p className="reviewName">
                        <span>{it.memName} 님</span>                    
                        <span>{it.day}</span> 
                    </p>
                    <p className="reviewContents">{it.content}</p>
                </li>
            ))} 
        </ul>
    </div>
    )

아주 아주 간단하게 props로 state 변수였던 data를 전달해주고, map메서드를 이용해준다.

이때 data값이 존재할때만 실행될 수 있도록 data?.map()이라고 적어준다 .

 

여기까지 됐다면 댓글을 작성했을 때 실시간으로 리스트에 추가되는 것을 볼 수 있다.

댓글 작성

 

실시간 추가

 

순서는 sort 메서드를 사용하여 최신순으로 정렬되게 하였다.

 

마지막으로 작성할 때 날짜를 오늘 날짜로 설정해보겠다.

        axios.post('http://localhost:3001/review',{ 
            memName: memInfo[0].memName ,
            memId:  memInfo[0].memId ,
            day: new Date().toLocaleDateString() ,
            content:  refText.current.value 
        })

 

오늘 날짜로 추가되지만 다른 댓글들과 구성이 다르다.

 

2024-xx-xx 처럼 날짜를 설정하기위해 util.js를 만들었다.

export const getFormatttedDate = (targetDate)=>{
    let year = targetDate.getFullYear();
    let month = targetDate.getMonth() + 1;
    let date = targetDate.getDate();
    if(month < 10){
        month = `0${month}`;
    }
    if (date < 10){
        date = `0${date}`;
    }
    return `${year}-${month}-${date}`;
}

export default getFormatttedDate;

 

저장해두고 필요할때마다 꺼내 쓰는 util 함수이다.

 

이제 함수를 불러와서 적용해주면 된다.

import getFormatttedDate from "./util";
(...)
        axios.post('http://localhost:3001/review',{ 
            memName: memInfo[0].memName ,
            memId:  memInfo[0].memId ,
            day: getFormatttedDate(new Date) ,
            content:  refText.current.value 
        }) 
(...)

 

이렇게 적용했다면 원하는 구성대로 적용된 것을 볼 수 있다.

다른 구성으로 바꾸고 싶다면 getFormatttedDate 함수의 날짜 구성을 수정하면 된다. 

 

 

이 다음엔 나의 댓글 삭제, 좋아요 버튼까지 추가하고 마이페이지까지 진행해보겠다.