앞에까지의 프로젝트는 저장기능이 따로 없다. 즉, 브라우저를 닫거나 새로고침하면 기존의 데이터가 초기화된다. 그렇다면 todolist의 용도를 못하는게 아닌가... 원래라면 데이터베이스를 구축해 데이터를 저장하고 불러오는게 맞다. 하지만 이번에는 리액트만 사용해서 기능을 구현하는것을 목표로 하겠다 절대 여러개 하기 싫어서가 아님!
데이터베이스 대신 선택한 방법은 localstorage이다. 이 저장공간은 브라우저 자체 저장공간으로 5mb의 크기를 가지고 있다. 이곳에 저장된 데이터를 확인하는 방법은

우클릭을 하면 콘솔창을 비롯한 브라우저 상세내용을 확인할수 있다. 그중에

application 페이지에가면 localstorage를 확인할 수 있다.
이곳에 데이터가 저장되는 것이다.
우리가 저장해야 할 데이터는 객체타입, 배열을 저장해야 한다. 하지만 localstorage에 데이터를 저장할때 그냥 저장할 수 없다. 원시타입의 데이터는 바로 저장이 가능하지만 객체타입의 데이터는 별도의 데이터 변환을 시켜줘야한다. 그럴때 사용하는 것이 JSON 이다.
JSON은 자바스크립트 객체 문법으로 데이터를 표기하는 언어이다. 텍스트 형식으로 데이터를 표기하기 때문에 데이터를 저장하고 교환하는데 자주 사용된다.

이건 리액트의 기본적인 정보를 담고있는 package.json파일이다. 이런 방식으로 배열이나 객체 등의 데이터를 변환하게 된다.
그래서 우리도 todolist의 데이터를 저장하고 불러오기 위해 JSON을 사용해 보겠다.
JSON을 변환하는 것은 쉽다.
데이터 -> JSON
JSON.stingify()JSON -> 데이터
JSON.parse()
괄호에 변환할 데이터를 넣어주면 끝난다. 이렇게 변환한 데이터를 localstorage에 저장할 것이다.
로컬스토리지에 데이터 저장
localStorage.setItem('저장명',data)
괄호에는 저장할 이름과 데이터를 넣어주면 로컬 스토리지에 지정한 이름으로 데이터가 저장된다.

해당 데이터는 todos라는 이름으로 데이터명을 지정하고 배열을 저장한 것이다.
로컬스토리지에서 데이터 추출하는 법도 간단하다.
localStotage.getItem('저장명')
이러면 localstorage에 저장되있는 데이터를 불러올수 있다.
이제 프로젝트에 적용해보겠다.
우선 저장하는 시점은 해야할 일, 즉 배열이 추가되거나 value값이 수정되었을때 새로운 배열을 저장해주어야한다.
todolist 추가
const addItem = ()=>{ if(inputValue === ''){ alert('한글자 이상 입력해 주세요.'); } else{ const todos = { id: nextId.current, inputValue }; const addList = [...todoList,todos]; setTodoList(addList); localStorage.setItem('todos',JSON.stringify(addList)); nextId.current += 1; setInputValue(''); }; };
setTodoList를 통해 새로운 배열을 state값으로 저장하고JSON으로 변환해준 후todos라는 이름으로 localstorage에 저장해준다.배열이 수정되거나 삭제되었을 때에도 똑같다.
배열 삭제 및 수정
const removeItem = (id)=>{ let removelist = todoList.filter((todo) => todo.id !== id); setTodoList(removelist); localStorage.setItem('todos',JSON.stringify(removelist)); }; const editItem = (id)=>{ let edit = prompt('수정할 내용을 입력하세요'); let editList = todoList.map((todo) => todo.id === id ? {...todo, inputValue: edit} : todo); setTodoList(editList); localStorage.setItem('todos',JSON.stringify(editList)); };
수정 배열으로 바꿔준 후 로컬스토리지에 저장해주면 된다.
이제 데이터를 불러오는 시점은 페이지가 처음 시작될 때 불러온다. 그래서 나는 메인 페이지인 Home.js에서 불러온다.
데이터 불러오기
import React, { useEffect } from 'react'; import { useState,useRef } from 'react'; import TodoInput from '../components/todoinput'; import TodoBoard from '../components/todoboard'; function Home() { const [inputValue,setInputValue] = useState(''); const [todoList,setTodoList] = useState([]); const nextId = useRef(1); useEffect(()=>{ const localList = localStorage.getItem('todos'); if(localList !== 0){ setTodoList(JSON.parse(localList))}; },[]); return( <div className="main"> <TodoInput inputValue={inputValue} setInputValue={setInputValue} todoList={todoList} setTodoList={setTodoList} nextId={nextId}/> <TodoBoard todoList={todoList} inputValue={inputValue} setInputValue={setInputValue} setTodoList={setTodoList}/> </div> ); }; export default Home;
일반적으로 불러서 데이터를 가져와도 되지만 다른 방법을 사용하겠다.
useEffect는 리액트에서 사용하는 hook이다.
- 컴포넌트가 처음 실행(마운트)될때에 함수 실행
- state값의 변화가 있을때 함수 실행
이러한 용도로 사용을 하게된다.
그럼 todolist에서 사용하는 목적에 대해서 생각해보겠다. useEffect를 통해 우리가 실행시킬 함수는 로컬스토리지에 있는 데이터를 가져오는 것이다. 데이터를 불러오는건 처음 페이지를 렌더링할때에만 필요하다. 만약 처음 데이터를 불러오지 않는다면 빈 화면만 렌더링되기 때문이다.
useEffect의 사용법은 간단하다.
useEffect(()=>{ console.log('컴포넌트 실행'); // 1번 return()=>{ console.log('컴포넌트 실행 완료') // 2번 }; },[]); // 3번
1번은 컴포넌트 실행시 실행할 함수이다.
2번은 cleanup함수로 컴포넌트 종료시 실행할 함수이다.
3번은 deps로 특정 값과 배열을 넣으면 변화를 감지해 리렌더링을 진행한다.만약 위의 코드처럼 빈 배열을 넣으면 처음 실행시에만 1번의 함수를 실행한다. 우리는 todolist에서 처음 한번만 데이터를 불러올거기 때문에
useEffect(()=>{
const localList = localStorage.getItem('todos');
if(localList !== 0){
setTodoList(JSON.parse(localList))};
},[]);
localstorage에서 todos라는 이름의 데이터를 localList라는 변수에 저장하고 localList의 배열이 존재할때 JSON데이터를 변환해 state값으로 설정하는 함수를 작성했다. deps의 배열이 비어있기 때문에 처음 렌더링될때만 실행이 되서 불필요한 데이터 송신이 발생하지 않는다.
이렇게 todolist의 전반적인 기능을 다 구현했다. 작성한지 시간이 지난 코드이기도 하고 이후에 익숙하게 쓰던 코드를 하나씩 정리하고 구현하려니 쉽지않았다. 포스트가 점점 길어지다보니 더 설명해야하는 부분들도 생략한게 많다. 하지만 앞으로 안쓰는 기능들도 아니다보니 조금씩 설명을 이어나가 보겠다.
다음은 리액트에서 핵심적인 라이브러리인 react-router-dom을 사용해 싱글페이지를 만들어 보겠다!