Study/React

[ReactJS/AXIOS] 백엔드 없이 로그인 구현하기 (3) (+댓글 작성, LocalStorage 암호화)

hyjang 2024. 7. 3. 21:18
728x90

지난 포스팅에서 로그인, 로그아웃까지 만들었다. 

이번엔 로그인한 상태에서 댓글을 달면 좌측에 리스트에 추가 시켜볼 것이다.

 

댓글 리스트 불러오기

좌측(댓글 리스트) / 우측(댓글 작성란)

 

먼저 data.json 파일에 리뷰 리스트에 해당되는 데이터 배열을 추가한다.

로컬로 접속할 때

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

로컬에서 본 데이터와 작성한 코드

 

이제 이 데이터를 불러와서 댓글 리스트에 추가해준다.

 

이전에 만들어두었던 useFetch를 사용하여 데이터를 얻어온다.(GET)

 import useFetch from '../hooks/useFetch'

export default function ReviewList(){ 
    const item = useFetch('http://localhost:3001/review'); 
    return(
        <div className="reviewList">
        <ul>
            {item.map((it)=>(
                <li key={it.id}>
                    <p className="reviewName">
                        <span>{it.memName} 님</span>                    
                        <span>2024-05-32</span> 
                    </p>
                    <p className="reviewContents">{it.content}</p>
                </li>
            ))} 
        </ul>
    </div>
    )
}

 

처음에 이런식으로 코드를 넣었더니 TypeError: item.map is not a function 오류가 생겼다.

위에 오류는 보통 item이 Array(배열) 타입이 아닐 때 나오는 오류인데,

console.log(item)을 넣어보니 아래처럼 Object 타입으로 들어가있었다.

 

 

저 데이터 중에서 data를 가져와야하기 때문에 item.data.map()으로 써줘야했다.

그리고 data 배열이 존재할 때만 적용이 가능하도록 item.data?map()으로 작성해줘야 한다.

 

fetch를 사용할 때는 data를 추가로 쓰지 않아도 됐는데, axios는 필요한 부분까지 적는것에 익숙해져야할 것 같다.

 

 import useFetch from '../hooks/useFetch'

export default function ReviewList(){ 
    const item = useFetch('http://localhost:3001/review'); 
    return(
        <div className="reviewList">
        <ul>
            {item.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>
    )
}

 

최종적으로 위에 코드처럼 적용을 해주니 정상적으로 댓글 리스트에 적용됐다.

 


LocalStorage로 로컬에 데이터 저장하기 

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

 

review 데이터들을 보면 내가 "memId"를 추가한 것이 보인다.

누가 댓글을 썼는지 확인할 수 있도록, 그리고 내가 쓴 댓글이면 지우거나 수정할 수 있도록 하기 위해서 추가해뒀다.

 

그럼 로그인 한 사용자(나)의 memId값을 어떻게 받아와야 할까?

 

나는 여기서 LocalStorage를 사용하여 로컬에 memId 를 저장하고, 댓글의 memId와 일치한다면 삭제를 할 수 있도록 할 것이다.

 

로컬스토리지 사용법

// 데이터 저장하기
localStorage.setItem("key", value);

// 데이터 읽기
localStorage.getItem("key");

// 데이터 삭제
localStorage.removeItem("key");

// 모든 데이터 삭제
localStorage.clear();

// 저장된 키/값 쌍의 개수
localStorage.length;

 

💡로컬스토리지는 탭끼리 데이터를 공유할 수 있고, 일정 기간이 지나야 지워진다. 
     따라서 탭을 이동하거나 닫아도 데이터가 유지될 수 있다. 

 

 

데이터를 저장하려면 먼저 로그인할 때부터 저장이 돼야해서 다시 LogIn.js를 수정했다.

(...)
function onSubmit(){
        axios.post('http://localhost:3001/members',{id, pw})
        .then((res)=>{ 
            const result = item.data.find((item)=> item.memId === id && item.memPw === pw); 
            if(result){ 
                navigate('/')
                LogInFunc(true); 
                localStorage.setItem("memId", JSON.stringify(res.data));  
                const memInfo = JSON.parse(localStorage.getItem("memId")); 
                console.log(memInfo.id); 
            }else{ 
(...)

 

💡 객체 형식인 localstorage를 배열로 저장해야한다면  JSON.stringify()로 감싸준다. 
불러올 때는 다시 객체 형식으로 불러오기 위해서 JSON.parse()로 감싸줘야한다.

 

 

이대로 로그인을 다시 해보면

setItem key:value 값 불러오기
getItem value 중 id 값 불러오기

 

이제 JSON.parse(localStorage.getItem("memInfo")) 를 어떤 컴포넌트에서 사용해도 정보를 내 로컬에서 불러올 수 있다.

 

나는 id와 동일한 정보를 가진 전체 데이터를 불러올 예정이다.

  (...)
    function onSubmit(){
        axios.post('http://localhost:3001/members',{id, pw})
        .then((res)=>{ 
            const result = item.data.find((item)=> item.memId === id && item.memPw === pw);  
            if(result){ 
                navigate('/')
                LogInFunc(true); 
                const memInfo = item.data.filter((it)=> it.memId === id );
                localStorage.setItem("memInfo", JSON.stringify(memInfo)); 
  (...)

위와 같이 filter 메서드를 사용하면 로그인이 성공했을 때, id와 동일한 값을 가진 데이터를 필터링하여 로컬스토리지에 저장할 수 있다. 

 

 누구나 볼 수 있는 나의 로컬스토리지에 비밀번호 및 개인정보가 다 보이는건 불안하다.

찾아보니 데이터를 암호화 시켜주는 React Secure Storage 라이브러리가 있었다.

조금이나마 보안을 해결할 수 있도록 해당 라이브러리를 사용해준다. 

 

React Secure Storage 사용법

사용방법은 간단하다.

라이브러리를 설치해준다.

npm i react-secure-storage

 

import로 불러온다.

import secureLocalStorage from "react-secure-storage";

 

localstorage로 작성한 부분을 secureLocalStorage로 바꿔주고 stringify도 없애준다. 

(객체 형식인 localstorage와 다르게 secureLocalStorage는 문자열, 객체, 숫자, 불리언 값 형식이다.)

(...)
    function onSubmit(){
        axios.post('http://localhost:3001/members',{id, pw})
        .then((res)=>{ 
            const result = item.data.find((item)=> item.memId === id && item.memPw === pw);  
            if(result){ 
                navigate('/')
                LogInFunc(true); 
                const memInfo = item.data.filter((it)=> it.memId === id );
                secureLocalStorage.setItem("memInfo", memInfo ); 
(...)

 

여기서 만약 memId값만 가져오고 싶다면

const memmem = secureLocalStorage.getItem("memInfo")
                console.log(memmem[0].memId)

위의 코드를 사용해서 불러올 수 있다. (엄청난 시행착오가 있었다.)

 

위처럼 코드를 적고 데이터를 불러올 때, 암호화된 값이 아닌 원래의 값으로 복호화되어 나온다면 정상적으로 작동한 것이다.

 

이제 다음 포스팅에선 댓글을 작성하여 리스트에 추가하는 것을 해볼 것이다.