React에서 로컬스토리지 연결하기

React에서 영화 찜(하트) 기능을 만들면서 로컬스토리지(localStorage)에 배열을 안전하게 저장하고 꺼내는 방법, 그리고 || "[]"를 쓰는 이유와 함께 정리했습니다.


1. || "[]"를 추가한 이유

  • 로컬스토리지에서 값을 꺼낼 때
    localStorage.getItem("WatchList")는 저장된 값이 없으면 null을 반환합니다.
  • null을 바로 JSON.parse에 추가했을 경우
    JSON.parse(null)null을 반환해서 에러는 안 나지만,
    undefined"undefined" 같은 잘못된 값이 들어가면 에러가 납니다.
  • 빈 배열로 안전하게 시작하기
    localStorage.getItem("WatchList") || "[]"처럼 써주면,
    값이 없을 때 항상 빈 배열 문자열로 대체되어 JSON.parse("[]")[]를 반환합니다.

2. 안전하게 로컬스토리지 배열을 꺼내는 코드

const savedList = localStorage.getItem("WatchList") || "[]";
let watchList = [];
try {
  watchList = JSON.parse(savedList);
  if (!Array.isArray(watchList)) watchList = [];
} catch (e) {
  watchList = [];
}
  • 값이 없거나, 잘못 저장된 경우에도 무조건 배열로 만들어줍니다.
  • 이렇게 하면 .some(), .filter() 등 배열 메서드를 안전하게 사용 가능합니다.

3. 구현 코드

import React, { useEffect, useState } from "react";
import pinkHeart from "../../imgs/pinkheart.png";
import greyHeart from "../../imgs/greyheart.png";

const Ranking = ({ movie }) => {
  const [isClicked, setIsClicked] = useState(false);

  // 컴포넌트가 처음 나타날 때, 이 영화가 찜 목록에 있는지 확인
  useEffect(() => {
    const savedList = localStorage.getItem("WatchList") || "[]";
    let watchList = [];
    try {
      watchList = JSON.parse(savedList);
      if (!Array.isArray(watchList)) watchList = [];
    } catch (e) {
      watchList = [];
    }
    const found = watchList.some((item) => item.id === movie.id);
    setIsClicked(found);
  }, [movie.id]);

  // 하트 버튼 클릭 시
  const handleClick = () => {
    const savedList = localStorage.getItem("WatchList") || "[]";
    let watchList = [];
    try {
      watchList = JSON.parse(savedList);
      if (!Array.isArray(watchList)) watchList = [];
    } catch (e) {
      watchList = [];
    }

    if (isClicked) {
      // 이미 찜한 상태: 제거
      const myList = watchList.filter((item) => item.id !== movie.id);
      localStorage.setItem("WatchList", JSON.stringify(myList));
      setIsClicked(false);
    } else {
      // 찜하지 않은 상태: 추가
      const newList = [...watchList, movie];
      localStorage.setItem("WatchList", JSON.stringify(newList));
      setIsClicked(true);
    }
  };

  const heartImg = isClicked ? pinkHeart : greyHeart;

  return (
    <div>
      <p>{movie.title}</p>
      <img src={heartImg} onClick={handleClick} alt="찜하기" />
    </div>
  );
};
  • 하트는 isClicked 값에 따라 분홍/회색이 바뀝니다.
  • 찜 추가/제거 시 로컬스토리지와 상태를 모두 바꿔야 화면이 즉시 반영됩니다.

정리

  • 로컬스토리지에서 배열을 꺼낼 때는 항상 || "[]"를 붙입니다.
  • 이렇게 하면 값이 없거나 잘못된 값이 들어가도 에러 없이 빈 배열로 시작할 수 있습니다.
  • 배열 메서드를 쓸 때도 안전하다.
  • 키 이름(예: "WatchList")은 항상 일관되게 사용해야 합니다.
728x90

'무비넷' 카테고리의 다른 글

웹앱 성능 최적화  (0) 2025.09.02
[React] 클릭시 이미지 변경하기  (0) 2025.05.28
[React]리액트 타입 연결  (0) 2025.05.23
프롭스 연결하기  (0) 2025.05.22
프로젝트 시작  (0) 2025.05.08

로컬 스토리지란?

로컬스토리지는 브라우저에 정보를 저장하는 기능입니다.
예를 들어, 내가 입력한 데이터를 새로고침해도 남아있게 하고 싶을 때 사용할 수 있습니다.
내 컴퓨터 브라우저에 데이터를 저장하는 상자라고 생각할 수 있습니다.

    • 브라우저를 껐다 켜도 데이터가 존재합니다.
    • 문자(문자열)만 저장할 수 있습니다.
    • 로그인 정보, 테마 설정, 임시 데이터 저장 등에 사용합니다.
    • 로컬스토리지는 문자(문자열)만 저장할 수 있습니다.

그러나, 우리가 사용하는 객체배열은 문자열이 아니기 때문에 바로 저장할 수 없으므로

저장할 때는 JSON.stringify()로 문자열로 바꿔서 저장하고

불러올 때는 JSON.parse()로 다시 원래 객체/배열로 변환해야 합니다.

 

로컬스토리지 사용법

1. 데이터 저장하기

// 'username'이라는 이름으로 '김강현' 저장
localStorage.setItem('username', '김강현');

2. 데이터 불러오기

// 'username'이라는 이름의 데이터 꺼내오기
const name = localStorage.getItem('username');
console.log(name); // '김강현'

3. 데이터 삭제하기

// 'username' 데이터 삭제
localStorage.removeItem('username');

4. 객체 저장 & 불러오기

// 객체를 문자열로 변환해서 저장
const user = { name: '김강현', age: 30 };
localStorage.setItem('user', JSON.stringify(user));

// 저장된 데이터는 실제로 이렇게 보입니다:
// '{"name":"김강현","age":30}'

// 불러올 때는 다시 객체로 변환
const savedUser = JSON.parse(localStorage.getItem('user'));
console.log(savedUser.name); // '김강현'
console.log(savedUser.age);  // 30

5. 배열 저장 & 불러오기

// 배열을 문자열로 변환해서 저장
const fruits = ['사과', '바나나', '포도'];
localStorage.setItem('fruits', JSON.stringify(fruits));

// 불러올 때는 다시 배열로 변환
const savedFruits = JSON.parse(localStorage.getItem('fruits'));
console.log(savedFruits[0]); // '사과'

정리

  • 로컬스토리지는 브라우저에 간단한 정보를 저장할 때 사용합니다.
  • 문자열만 저장 가능하므로 객체/배열은 JSON.stringifyJSON.parse를 꼭 사용해야 합니다.
  • 새로고침이나 브라우저를 껐다 켜도 데이터가 남아있어서 편리합니다.
  • 브라우저에 데이터가 존재하므로 중요한 개인정보(비밀번호, 토큰 등)등의 저장에 주의해야 합니다.
리액트에서는 useEffectuseState를 활용해 로컬스토리지와 상태를 연동할 수 있습니다.
(입력값을 저장하고, 새로고침해도 입력값이 남아있게 만들기가 가능합니다.)
728x90

'React' 카테고리의 다른 글

[Konva.js] 드래그 앤 드롭과 객체 변형 구현하기  (2) 2025.07.27
[React] Props(프롭스)란?  (0) 2025.05.28
[React] 리액트 타입 연결하기  (0) 2025.05.28
[React] UseState란?  (0) 2025.05.27
[React] UseMemo란?  (0) 2025.05.22

데이터 관리


데이터가 대량으로 생성되고 활용되는 시대에, 데이터를 체계적으로 저장하고 보관하며 효율적으로 활용하는 일은 매우 중요하다. 데이터 관리는 데이터의 저장, 검색, 보안, 품질 유지 등 전 과정을 포함하며, 데이터베이스와 파일 시스템, 클라우드 스토리지 등 다양한 방식이 사용된다.

1. 데이터 관리의 주요 목적

  • 데이터의 안전한 저장과 신속한 검색, 그리고 데이터의 품질과 보안을 유지하는 것이 핵심이다.
  • 데이터의 중복을 줄이고, 일관성을 확보하며, 필요한 정보를 빠르게 찾을 수 있도록 체계적으로 관리해야 한다.

2. 데이터베이스와 데이터 관리 시스템

데이터베이스는 대량의 데이터를 효율적으로 저장·검색·수정·삭제할 수 있도록 설계된 시스템이다. 데이터베이스 관리 시스템(DBMS)은 데이터의 구조와 접근 방식을 통제하며, 데이터의 무결성과 보안을 보장한다.

구분 특징 예시
관계형 데이터베이스 테이블(행/열) 구조, SQL로 데이터 관리 MySQL, Oracle, PostgreSQL
NoSQL 비정형/대용량 데이터에 적합, 유연한 구조 MongoDB, Redis, Cassandra
클라우드 스토리지 인터넷 기반 저장, 확장성·접근성 우수 AWS S3, Google Drive

3. 데이터 관리의 주요 기능

  • 데이터의 저장과 백업, 신속한 검색과 조회, 접근 권한 관리, 데이터 품질 유지, 정기적인 유지보수 등이 포함된다.
  • 데이터의 무결성(정확성, 일관성)과 보안(접근제어, 암호화, 백업/복구)이 중요하다.

4. 데이터 관리의 최신 트렌드

  • 클라우드 기반 데이터 관리로 언제 어디서나 데이터 접근이 가능해졌다.
  • 빅데이터 환경에서는 분산 저장, 병렬 처리, 데이터 거버넌스(정책, 표준, 품질관리)가 강조된다.

5. 용어 정리

  • DBMS: 데이터베이스 관리 시스템, 데이터의 저장·검색·보안·무결성 관리
  • 정규화: 데이터 중복 최소화, 구조 최적화
  • 데이터 거버넌스: 데이터 관리 정책, 표준, 책임 체계
  • 백업/복구: 데이터 손실에 대비한 저장/복원

정리

데이터 관리가 잘 되어야 데이터의 신뢰성과 활용도가 높아진다. 데이터베이스, 클라우드, 빅데이터 등 다양한 환경에서 데이터의 저장, 보안, 품질 관리가 모두 중요하며, 데이터를 안전하게 보관하고 효율적으로 활용하는 체계적인 관리가 데이터 기반 분석과 의사결정의 토대가 된다.
728x90

'데이터사이언스' 카테고리의 다른 글

데이터 전처리  (0) 2025.05.31
데이터 탐색  (0) 2025.05.29
데이터 수집  (0) 2025.05.26
데이터사이언스의 기반지식 학습  (0) 2025.05.23
데이터사이언스의 기본 개념  (0) 2025.05.20

리액트 Props(프롭스)란?

Props는 "properties"의 줄임말로, 부모 컴포넌트가 자식 컴포넌트에 값을 전달할 때 사용하는 데이터입니다.
함수의 매개변수처럼, 컴포넌트에 값을 넘겨주고, 자식 컴포넌트는 그 값을 받아서 화면에 표시하거나 로직에 사용할 수 있습니다.
props는 읽기 전용이며, 자식 컴포넌트에서 직접 값을 변경할 수 없습니다.


Props 사용법

1. 부모 컴포넌트에서 값 전달

function Parent() {
  return <Child name="김강현" age={30} />;
}
  • nameage라는 props를 Child 컴포넌트에 전달합니다.
  • 문자열은 따옴표("), 숫자나 변수, 객체는 중괄호({})로 감쌉니다.

2. 자식 컴포넌트에서 props 받기

function Child(props) {
  return (
    <div>
      <p>이름: {props.name}</p>
      <p>나이: {props.age}</p>
    </div>
  );
}
  • 함수의 첫 번째 인자로 props 객체를 받습니다.
  • props.이름으로 전달받은 값을 사용할 수 있습니다.

3. 구조분해 할당으로 props 받기

function Child({ name, age }) {
  return (
    <div>
      <p>이름: {name}</p>
      <p>나이: {age}</p>
    </div>
  );
}
  • props 객체에서 필요한 값만 바로 꺼내서 사용할 수 있어 코드가 더 간결해집니다.

4. 변수/객체/배열도 전달 가능

function Parent() {
  const user = { name: "김강현", age: 30 };
  return <Child user={user} />;
}

function Child({ user }) {
  return (
    <div>
      <p>이름: {user.name}</p>
      <p>나이: {user.age}</p>
    </div>
  );
}

5. props를 활용한 컴포넌트 재사용

function Button({ label, color }) {
  return <button style={{ color: color }}>{label}</button>;
}

function App() {
  return (
    <div>
      <Button label="저장" color="blue" />
      <Button label="취소" color="red" />
    </div>
  );
}
  • props를 다르게 주면 같은 컴포넌트도 다양한 역할을 할 수 있습니다.

정리

  • props는 부모 → 자식 방향으로 데이터를 전달하는 통로입니다.
  • props는 읽기 전용입니다(자식에서 직접 변경 불가).
  • props를 활용하면 컴포넌트를 더 재사용성 있게 만들 수 있습니다.
  • props는 컴포넌트의 "함수 인자"와 같은 역할을 합니다.

Tip: props의 타입을 명확히 하고 싶다면 PropTypes 또는 TypeScript를 활용할 수 있습니다.
(예시: Child.propTypes = { name: PropTypes.string.isRequired };)

728x90

React에서 버튼 클릭시 색상 변경하기

React로 하트(좋아요) 버튼을 구현할 때 어떤 훅을 사용할지 고민하였습니다.

아래는 useState와 useMemo의 차이점을 비교하고, 하트 버튼에서 활용하는 과정입니다.


useState

useState는 React의 내장 Hook으로, 함수형 컴포넌트에서 상태를 관리할 수 있게 해주는 기능입니다. useState를 사용하면 시간이 지남에 따라 변경될 수 있는 값을 저장하고 관리할 수 있습니다.

useState 기본 사용법

const [상태 변수, 상태 변경 함수] = useState(초기값);

useState 함수에 초기 상태 값을 매개변수로 호출하면 배열이 반환됩니다. 이 배열에는 현재 값을 나타내는 상태 변수와 상태 값을 변경하는데 사용하는 함수가 들어가 있습니다.

useState로 구현하기

가장 기본적이고 직관적인 방법은 useState를 사용하는 것입니다.

import React, { useState } from "react";

const Ranking = () => {
  const [isClicked, setIsClicked] = useState(false);

  const handleClick = () => setIsClicked((prev) => !prev);

  // 상태에 따라 하트 이미지 경로를 결정
  const heartImg = isClicked
    ? "src/imgs/pinkheart.png"
    : "src/imgs/greyheart.png";

  return (
    <img
      src={heartImg}
      alt="heart"
      onClick={handleClick}
      style={{ cursor: "pointer" }}
    />
  );
};

export default Ranking;

함수형 업데이트를 사용하는 이유

상태 변경 함수에는 두 가지 방식이 있습니다:

  1. 값 업데이트: setIsClicked(true)
  2. 함수형 업데이트: setIsClicked(prev => !prev)

함수형 업데이트 방식을 권장하는 이유는 React의 상태 변경 함수가 비동기적으로 동작하기 때문입니다. setCount 함수를 호출하는 시간과 상태가 실제로 업데이트되는 사이에 지연이 있을 수 있어, 함수형 업데이트를 사용하면 버그를 방지하고 성능을 개선할 수 있습니다.


useMemo

useMemo는 재렌더링 사이에 계산 결과를 캐싱할 수 있게 해주는 React Hook입니다. 주로 비용이 많이 드는 연산을 수행할 때 사용되며, 메모이제이션(memoization) 기술을 통해 중복 계산을 피하고 성능을 최적화합니다.

useMemo 기본 사용법

const cachedValue = useMemo(calculateValue, dependencies);

useMemo의 첫 번째 인자는 실행할 함수이고, 두 번째 인자는 의존성 배열입니다. 이 배열의 값이 변경될 때만 함수가 다시 실행됩니다.

useMemo로 구현하기

useMemo를 사용해서 하트 이미지 경로를 관리할 수도 있습니다:

import React, { useState, useMemo } from "react";

const Ranking = () => {
  const [isClicked, setIsClicked] = useState(false);

  // useMemo로 이미지 경로를 관리
  const heartImg = useMemo(
    () => (isClicked ? "src/imgs/pinkheart.png" : "src/imgs/greyheart.png"),
    [isClicked]
  );

  const handleClick = () => {
    setIsClicked((prev) => !prev);
  };

  return (
    <img
      src={heartImg}
      alt="heart"
      onClick={handleClick}
      style={{ cursor: "pointer" }}
    />
  );
};

export default Ranking;

useState를 사용해야 하는 경우

  • 사용자 상호작용에 따라 값이 변해야 할 때
  • 컴포넌트 내부에서 상태를 직접 관리할 때
  • 간단한 상태 관리가 필요할 때

useState는 상태 관리의 기본이며, 클릭과 같은 사용자 상호작용을 처리하는 데 필수적입니다.

useMemo를 사용해야 하는 경우

useMemo는 주로 두 가지 목적으로 사용됩니다:

  1. 계산 비용이 높은 연산의 결과를 저장하고 재사용하기 위해
  2. 참조 동일성(Reference Equality)을 유지하기 위해

하지만 하트 버튼의 경우, 단순히 isClicked 값에 따라 이미지 경로가 바뀌는 것이므로 useMemo를 사용해도 성능상 큰 차이는 없습니다.


적용 사례

하트 버튼 구현에서 생각한 최선의 코드는 useState만 사용하는 것입니다.

import React, { useState } from "react";
import pinkHeart from "../../imgs/pinkheart.png";
import greyHeart from "../../imgs/greyheart.png";

const Ranking = () => {
  const [isClicked, setIsClicked] = useState(false);
  const handleClick = () => setIsClicked((prev) => !prev);

  return (
    <img
      src={isClicked?pinkHeart: greyHeart}
      alt="heart"
      onClick={handleClick}
      style={{ cursor: "pointer" }}
    />
  );
};

export default Ranking;
  1. 가독성: 코드가 간결하고 이해하기 쉽습니다.
  2. 유지보수성: 불필요한 복잡성이 없어 수정이 용이합니다.
  3. 성능: 단순한 조건 분기는 useMemo 없이도 충분히 빠릅니다.
  4. 메모리 효율성: useMemo는 이전 값들을 저장하므로 무분별하게 사용하면 메모리 사용 측면에서 비효율적입니다.

정리

  • useState: 상태 관리의 기본, 사용자 상호작용 처리에 필수
  • useMemo: 복잡한 계산이나 참조 동일성이 중요할 때 사용
  • 하트 토글 버튼: useState만으로도 충분하며, 이것이 가장 깨끗한 코드

React 개발에서는 적절한 도구를 적절한 곳에 사용하는 것이 중요합니다. 복잡함을 추가하지 않고 필요한 것에 최적화된

Hook을 사용합니다.

728x90

'무비넷' 카테고리의 다른 글

웹앱 성능 최적화  (0) 2025.09.02
로컬스토리지 연결(워치리스트 컴포넌트)  (0) 2025.05.29
[React]리액트 타입 연결  (0) 2025.05.23
프롭스 연결하기  (0) 2025.05.22
프로젝트 시작  (0) 2025.05.08