반응형

안녕하세요! 요즘 아이 코딩 교육에 관심이 많아서 코볼트 RC카를 체험해보게 되었어요. 마이크로비트를 활용한 코딩 RC카라고 해서 정말 기대가 컸는데, 직접 사용해보니 기대 이상이었답니다!

📦 개봉기 & 구성품 소개

택배로 받은 코볼트 RC카 박스를 열어보니 정말 깔끔하게 포장되어 있더라구요.

구성품 확인

  • 코볼트 RC카 본체 1대
  • USB 충전 케이블
  • 사용 설명서
  • 추가 액세서리 (별도 주문한 마이크로비트 v2.21)

박스를 열자마자 블랙과 블루 컬러 조합의 세련된 디자인이 눈에 띄었어요. 플라스틱 재질이지만 전혀 저렴해 보이지 않고, 마이크로비트가 딱 맞게 들어가는 설계가 인상적이었습니다.

앞쪽에 있는 초음파 센서 2개가 마치 귀여운 눈처럼 생겨서 아이가 보자마자 "로봇 같다!"며 좋아했어요.

🔧 RC카 조립 방식 및 리모컨 조작법

조립 과정

조립은 정말 간단했어요!

  1. 마이크로비트 장착: RC카 상단에 있는 슬롯에 마이크로비트를 꽂기만 하면 됩니다.
  2. 배터리 삽입: 18650 리튬 배터리를 본체 하단에 넣어주세요.
  3. 전원 켜기: 측면의 전원 스위치를 ON으로 돌리면 준비 완료!

정말 3분도 안 걸리는 간단한 과정이에요. 별도의 나사나 복잡한 조립이 필요 없어서 아이도 쉽게 할 수 있었답니다.

리모컨 조작법

코딩 RC카인 코볼트는 일반 RC카와 달리 프로그래밍으로 움직입니다.

MakeCode 에디터 사용법:

  1. 마이크로비트 MakeCode 웹사이트 접속
  2. 확장 URL 추가: https://github.com/LLY16888/Microbit_Car
  3. 코볼트 전용 블록들이 나타남
  4. 원하는 동작을 블록으로 조합
  5. 마이크로비트에 다운로드

처음에는 단순한 전진, 후진, 좌회전, 우회전부터 시작했는데 반응이 정말 빨랐어요!

 

실제로 코딩 RC카 코볼트가 움직이는 모습을 보니 정말 신기했어요. 150RPM 기어드 모터 덕분에 생각보다 속도감도 있고 파워풀하더라구요.

실내 주행 테스트: 거실에서 테스트해봤는데 카펫 위에서도 부드럽게 잘 굴러갔어요. 특히 자율주행 모드로 설정하니 테이블 다리나 소파 같은 장애물을 스스로 피해가는 모습이 정말 똑똑해 보였답니다.

야외 주행 테스트: 베란다에서도 테스트해봤는데 실내보다 더 시원하게 달리더라구요. 바닥이 매끄러워서 더 빠른 속도로 움직일 수 있었어요.

주행 중에 아이가 가장 신기해했던 건 초음파 센서로 장애물을 감지하는 기능이었어요. 벽 앞에서 자동으로 멈추고 방향을 바꾸는 모습을 보고 "진짜 스스로 생각하는 것 같다"며 감탄했답니다.

🎯 자율주행 도전기

제일 재미있었던 건 역시 자율주행 기능이었어요. 초음파 센서로 장애물을 감지해서 피해가는 코드를 직접 만들어봤는데, 처음엔 벽에 계속 부딪히더라구요.

몇 번 수정하다 보니 점점 똑똑해지는 느낌이었어요. 거실 테이블 다리들 사이를 스르륵 피해가는 모습을 보니까 정말 신기했답니다.

아이와 함께 "만약 여기서 멈추면 어떻게 할까?" "벽이 너무 가까우면 어떻게 판단할까?" 이런 것들을 생각해보면서 코딩하는 재미를 알아가는 것 같아서 뿌듯했어요.

🧩 레고 호환성 체험

코딩 RC카 코볼트의 가장 큰 장점 중 하나가 바로 레고 호환성이에요!

집에 있던 레고 블록들을 위에 붙여서 나만의 RC카를 만들어봤는데 정말 재미있었어요. 레고 테크닉 부품들을 활용해서 굴삭기 모양으로 꾸며보니 완전 멋있더라구요.

아이가 직접 레고로 작은 집을 만들어서 RC카 위에 올려놓고 "이사가는 차"라고 하면서 가지고 놀더라구요. 이런 창의적인 놀이가 가능한 게 정말 좋은 것 같아요.

⚡ 충전과 배터리 관리

USB 충전이 정말 편리해요! 별도 충전기 없이 핸드폰 충전기 그대로 사용할 수 있어서 좋았어요.

완충하는데 약 2시간 정도 걸리고, 한 번 충전하면 1시간 이상 연속으로 사용할 수 있었어요. 아이와 충분히 놀기에는 부족함이 없는 시간이었답니다.

배터리 잔량도 마이크로비트 화면에 표시되어서 언제 충전해야 할지 미리 알 수 있어서 좋았어요.

🎓 교육적 효과

단순히 코딩 RC카로 놀기만 하는 게 아니라 정말 많은 걸 배울 수 있어요.

논리적 사고력: 어떤 순서로 명령을 내려야 원하는 대로 움직일지 생각하게 되더라구요.

문제해결능력: 원하는 대로 안 움직일 때 어디가 문제인지 찾아서 수정하는 과정이 정말 교육적이에요.

창의성: 레고와 결합해서 다양한 모양으로 꾸미고, 새로운 미션을 만들어볼 수 있어요.

과학적 호기심: 초음파 센서가 어떻게 작동하는지, 모터는 어떻게 바퀴를 돌리는지 자연스럽게 관심을 갖게 되더라구요.

💡 다양한 활용 방법

코볼트 코딩 RC카는 정말 다양하게 활용할 수 있어요.

미션 만들기: 집 안에 장애물 코스를 만들어서 통과하는 미션을 만들어봤어요.

경주 게임: 친구들과 함께 누가 더 빠르고 정확하게 목표점에 도착하는지 경쟁해볼 수 있어요.

춤추는 로봇: 음악에 맞춰 좌우로 움직이는 댄스 패턴을 프로그래밍해봤는데 정말 재미있었어요.

탐험 로봇: 집 안 곳곳을 돌아다니면서 사진을 찍는다는 설정으로 놀아봤어요.

🎨 확장성과 업그레이드

파이썬 위키도 제공되고, MakeCode뿐만 아니라 파이썬으로도 프로그래밍할 수 있다는 점이 정말 마음에 들어요.

나중에 아이가 더 커서 복잡한 프로그래밍을 배우고 싶어할 때도 계속 사용할 수 있을 것 같아요. 단순한 장난감이 아니라 성장하는 교육 도구라는 느낌이에요.

추가 센서나 액세서리도 구매할 수 있어서 더 다양한 기능을 추가해볼 수 있다는 점도 좋았어요.

🏆 총평

아이와 함께 주말 내내 정말 재미있게 가지고 놀았어요. 처음엔 단순한 RC카 정도로 생각했는데, 직접 코딩해서 움직이는 걸 보니까 성취감이 정말 크더라구요.

코딩을 전혀 모르는 상태에서 시작해도 MakeCode 블록 코딩이 직관적이라 금방 익힐 수 있었어요. 아이보다 제가 더 빠졌다는 게 함정이긴 하지만요!

앞으로 더 복잡한 미션들도 만들어보고 싶고, 레고랑 결합해서 더 멋진 모양으로도 만들어보고 싶어요.

코딩 교육용 교구를 찾고 계신다면 정말 추천드려요! 마이크로비트와 함께 구매하면 바로 시작할 수 있으니 참고하세요.

코볼트 RC카 덕분에 아이가 코딩에 대한 관심이 생겼고, 무엇보다 함께 문제를 해결해나가는 과정이 정말 의미 있는 시간이었어요.


 

#코볼트RC카 #코딩RC카 #교육용RC카 #RC카 #마이크로비트 #마이크로비트RC카 #ICBANQ

본 포스팅은 아이씨뱅큐로부터 제품을 제공받아 직접 체험 후 작성한 솔직한 후기입니다.

반응형
반응형

1. launch instance 로 ec2 생성

2. ubuntu 로 서버 이미지 생성 

3. security group 
처음 생성하는 경우 security group 생성, 이전에 만든 적 있으면 이전에 만든 security group 생성 

해당 security group 에서 inbound 편집을 추후 해줘야 합니다. 
ex ) 3306 port 추가 및 ssh 접속시 ip 허용 
anywhere 로 추가하면 어떤 ip 에서도 접속 가능 

4. key pair 생성

key 파일이 없으면 신규로 생성. 앞으로 해당 파일로 접속해야해서 분실하면 안됩니다. 


Ubuntu EC2 인스턴스에 MySQL 8.0을 설치

1. EC2 인스턴스에 접속

 

먼저 EC2 인스턴스에 SSH로 접속합니다. 로컬에서 다음 명령어를 사용하여 SSH 접속합니다:

ssh -i /path/to/your-key.pem ubuntu@your-ec2-public-ip

2. Ubuntu 패키지 업데이트

 

MySQL을 설치하기 전에, 패키지 목록을 업데이트합니다.

sudo apt update

 

3. MySQL 8.0 설치

 

MySQL 8.0은 Ubuntu의 기본 패키지 저장소에서 제공됩니다. 다음 명령어로 MySQL 8.0을 설치할 수 있습니다.

sudo apt install mysql-server -y

 

4. MySQL 서비스 시작

 

MySQL 서버가 설치되면, MySQL 서버를 시작합니다.

sudo systemctl start mysql

 

MySQL 서버가 부팅 시 자동으로 시작되도록 설정하려면 다음 명령어를 사용합니다.

sudo systemctl enable mysql

 

5. MySQL 기본 설정 및 보안

 

MySQL을 설치하면 보안 관련 기본 설정을 진행할 수 있습니다. 이를 위해 mysql_secure_installation 스크립트를 실행합니다.




sudo mysql_secure_installation

이 명령어는 다음과 같은 작업을 수행합니다:

 

루트 사용자 비밀번호 설정.

익명 사용자 삭제.

원격 루트 로그인 비활성화.

테스트 데이터베이스 삭제.

보안 설정 재로드.

6. MySQL 루트 사용자 비밀번호 설정

 

MySQL이 설치되면 루트 사용자의 비밀번호를 설정해야 합니다. 먼저 MySQL에 접속합니다.

sudo mysql

MySQL 프롬프트에서 다음 명령어를 사용하여 루트 사용자 비밀번호를 설정합니다.

ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'YourNewPassword';

이후 MySQL 프롬프트에서 빠져나갑니다.

EXIT;

7. MySQL 접속 테스트

 

설정한 비밀번호를 사용하여 MySQL에 접속할 수 있습니다.

mysql -u root -p

비밀번호를 입력한 후 MySQL 프롬프트로 접속할 수 있습니다.

 

8. 방화벽 및 보안 그룹 설정 (필요한 경우)

 

MySQL의 기본 포트인 3306을 외부에서 접근할 수 있도록 EC2 인스턴스의 보안 그룹에서 3306 포트를 허용해야 합니다.

 

1. AWS 콘솔에서 EC2 인스턴스의 보안 그룹으로 이동합니다.

2. **인바운드 규칙 (Inbound Rules)**에서 MySQL/Aurora 또는 TCP 포트 3306을 추가합니다.

Source는 허용할 IP 주소를 설정합니다 (예: 0.0.0.0/0은 모든 IP에서 접근 가능, 보안을 위해 특정 IP만 허용하는 것이 좋습니다).

 

9. MySQL 외부 접속 허용 (선택 사항)

 

기본적으로 MySQL은 외부 접속을 허용하지 않습니다. 외부에서 MySQL에 접속하려면 MySQL 설정 파일을 수정해야 합니다.

sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf

설정 파일에서 bind-address 항목을 찾은 후, 127.0.0.1을 EC2 인스턴스의 공인 IP로 변경하거나 모든 IP에서 접속 가능하게 하려면 0.0.0.0으로 변경합니다.

bind-address = 0.0.0.0

파일을 저장하고 MySQL 서버를 재시작합니다.

sudo systemctl restart mysql

 

 

 


java 설치

설치 확인

 

1. Ubuntu 패키지 목록 업데이트

 

먼저, 패키지 목록을 업데이트합니다. 최신 패키지를 설치할 수 있도록 항상 먼저 업데이트하는 것이 좋습니다.

sudo apt update

2. Java 17 설치

 

Java 17은 Ubuntu의 기본 패키지 저장소에서 설치할 수 있습니다.

sudo apt install openjdk-17-jdk -y

이 명령어는 OpenJDK 17 JDK(Java Development Kit)를 설치합니다.

 

3. Java 설치 확인

 

Java 17이 정상적으로 설치되었는지 확인하려면 다음 명령어를 사용합니다.

java -version

출력 결과는 다음과 유사하게 나타날 것입니다:

openjdk version "17.0.x" 
OpenJDK Runtime Environment (build 17.0.x+xx)
OpenJDK 64-Bit Server VM (build 17.0.x+xx, mixed mode)

 

 

 

반응형
반응형

Spring Boot에서 예외 처리 및 전역 예외 핸들러를 구현하는 코드를 통해, 다양한 예외 상황에서 일관된 응답을 제공하는 방법을 학습할 수 있습니다. 

@ControllerAdvice를 사용하여 전역 예외 처리기를 구현하고, 다양한 예외에 대해 적절한 응답을 반환하는 방법을 살펴보겠습니다.

 

1. 기본 예외 처리 설정

 

Spring Boot에서는 기본적으로 예외가 발생하면 HTTP 상태 코드와 함께 오류 메시지를 반환합니다. 하지만 이 기본 방식은 사용자 경험(UX)을 향상시키기 위해 커스터마이징이 필요할 수 있습니다.

 

2. 전역 예외 처리 클래스 생성

 

@ControllerAdvice를 사용하여 전역 예외 처리기를 생성합니다. 이 클래스는 애플리케이션 전반에서 발생하는 예외를 한 곳에서 처리하고, 일관된 방식으로 응답을 반환할 수 있게 합니다.

 

package com.example.demo.exception;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.WebRequest;

import java.util.HashMap;
import java.util.Map;

@ControllerAdvice
@RestController
public class GlobalExceptionHandler {

    // 1. 기본적인 예외 처리
    @ExceptionHandler(Exception.class)
    public final ResponseEntity<Object> handleAllExceptions(Exception ex, WebRequest request) {
        Map<String, Object> response = new HashMap<>();
        response.put("message", ex.getMessage());
        response.put("details", request.getDescription(false));
        return new ResponseEntity<>(response, HttpStatus.INTERNAL_SERVER_ERROR);
    }

    // 2. 특정 예외 처리 (예: NullPointerException)
    @ExceptionHandler(NullPointerException.class)
    public final ResponseEntity<Object> handleNullPointerException(NullPointerException ex, WebRequest request) {
        Map<String, Object> response = new HashMap<>();
        response.put("message", "Null value encountered!");
        response.put("details", request.getDescription(false));
        return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST);
    }

    // 3. 유효성 검사 실패 예외 처리 (예: MethodArgumentNotValidException)
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public final Map<String, String> handleValidationExceptions(MethodArgumentNotValidException ex) {
        Map<String, String> errors = new HashMap<>();
        ex.getBindingResult().getFieldErrors().forEach(error -> 
            errors.put(error.getField(), error.getDefaultMessage()));
        return errors;
    }

    // 4. 사용자 정의 예외 처리
    @ExceptionHandler(ResourceNotFoundException.class)
    public final ResponseEntity<Object> handleResourceNotFoundException(ResourceNotFoundException ex, WebRequest request) {
        Map<String, Object> response = new HashMap<>();
        response.put("message", ex.getMessage());
        response.put("details", request.getDescription(false));
        return new ResponseEntity<>(response, HttpStatus.NOT_FOUND);
    }
}

 

3. 사용자 정의 예외 클래스 생성

 

필요에 따라 사용자 정의 예외를 만들어 사용할 수 있습니다. 예를 들어, 리소스를 찾을 수 없을 때 발생시키는 예외를 만들 수 있습니다.

src/main/java/com/example/demo/exception/ResourceNotFoundException.java

package com.example.demo.exception;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

@ResponseStatus(value = HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {

    public ResourceNotFoundException(String message) {
        super(message);
    }
}

어노테이션을 사용하는 경우:

예외 클래스에 @ResponseStatus 어노테이션을 추가하면, 해당 예외가 발생할 때 Spring이 자동으로 지정된 HTTP 상태 코드를 반환합니다.

예를 들어, @ResponseStatus(HttpStatus.NOT_FOUND)를 사용하면, 이 예외가 발생할 때 자동으로 404 Not Found 상태 코드가 반환됩니다.

어노테이션을 사용하지 않는 경우:

@ResponseStatus 어노테이션을 사용하지 않으면, 예외 처리 클래스에서 ResponseEntity를 사용해 상태 코드를 명시적으로 설정할 수 있습니다. 이렇게 하면 예외 상황에 대해 더 유연한 처리가 가능합니다.

 

 

4. 예외 발생 시나리오

 

다음은 리소스를 찾지 못했을 때 ResourceNotFoundException을 발생시키는 서비스 코드의 예입니다.

 

src/main/java/com/example/demo/service/PostService.java

package com.example.demo.service;

import com.example.demo.entity.Post;
import com.example.demo.exception.ResourceNotFoundException;
import com.example.demo.repository.PostRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Optional;

@Service
public class PostService {

    @Autowired
    private PostRepository postRepository;

    public Post getPostById(Long id) {
        Optional<Post> post = postRepository.findById(id);
        if (!post.isPresent()) {
            throw new ResourceNotFoundException("Post not found with id: " + id);
        }
        return post.get();
    }

    // 기타 CRUD 메서드들...
}

5. 컨트롤러에서의 사용 예시

컨트롤러에서 서비스 메서드를 호출할 때, 예외가 발생하면 GlobalExceptionHandler가 이를 처리하여 일관된 응답을 반환합니다.

 

src/main/java/com/example/demo/controller/PostController.java

package com.example.demo.controller;

import com.example.demo.entity.Post;
import com.example.demo.service.PostService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/posts")
public class PostController {

    @Autowired
    private PostService postService;

    // GET /api/posts/{id} - Get a post by id
    @GetMapping("/{id}")
    public ResponseEntity<Post> getPostById(@PathVariable Long id) {
        Post post = postService.getPostById(id);
        return ResponseEntity.ok(post);
    }

    // 기타 CRUD 엔드포인트들...
}

 

반응형
반응형

Vue.js의 생성주기(lifecycle)는 Vue 인스턴스가 생성되어 DOM에 렌더링되고, 데이터가 변경되어 업데이트되는 과정에서 호출되는 일련의 메서드들입니다. 이 생성주기 훅들을 활용하면, 컴포넌트의 특정 단계에서 로직을 실행할 수 있습니다.

 

Vue 2와 Vue 3 모두 유사한 생성주기를 가지지만, Vue 3에서는 Composition API가 도입되면서 라이프사이클 훅이 약간 다른 형태로 사용됩니다. 여기서는 Options API와 Composition API 두 가지 스타일 모두에서 생성주기를 어떻게 활용하는지 설명하겠습니다.

 

1. Vue 인스턴스의 생명주기 (Options API 기준)

 

Vue 컴포넌트는 다음과 같은 주요 생명주기 단계를 거칩니다:

 

1) Before Create (beforeCreate)

 

설명: Vue 인스턴스가 초기화되기 전, data와 methods가 정의되기 전에 호출됩니다.

용도: 초기화 전에 실행할 코드를 작성할 수 있지만, data나 methods에 접근할 수 없습니다.

beforeCreate() {
  console.log('beforeCreate: 데이터와 메서드가 정의되기 전입니다.');
}

2) Created (created)

 

설명: Vue 인스턴스가 생성된 후, data와 methods가 초기화된 상태에서 호출됩니다. 이 시점에서 인스턴스는 반응형 상태입니다.

용도: API 호출, 초기 데이터 설정 등의 작업을 할 수 있습니다. 하지만 DOM에 접근할 수 없습니다.

created() {
  console.log('created: 인스턴스가 생성되고 data와 methods가 초기화되었습니다.');
}

3) Before Mount (beforeMount)

 

설명: 템플릿이 렌더링되기 전에 호출됩니다. DOM에 접근할 수 있지만, 아직 Vue가 DOM에 연결되지 않은 상태입니다.

용도: 렌더링 전에 DOM에 대해 작업할 필요가 있을 때 사용할 수 있습니다.

beforeMount() {
  console.log('beforeMount: 템플릿이 렌더링되기 전입니다.');
}

4) Mounted (mounted)

 

설명: Vue 인스턴스가 DOM에 마운트된 후 호출됩니다. 이 시점에서 템플릿은 DOM에 반영되었으며, 컴포넌트가 화면에 나타납니다.

용도: 컴포넌트가 DOM에 연결된 후 초기화 작업을 하거나, 외부 라이브러리를 초기화할 때 사용할 수 있습니다.

mounted() {
  console.log('mounted: 인스턴스가 DOM에 마운트되었습니다.');
}

5) Before Update (beforeUpdate)

 

설명: 반응형 데이터가 변경되어 DOM이 업데이트되기 직전에 호출됩니다.

용도: 데이터가 변경되었지만 DOM에 반영되기 전에 작업을 수행할 수 있습니다.

beforeUpdate() {
  console.log('beforeUpdate: 데이터가 변경되었고 DOM이 업데이트되기 전입니다.');
}

6) Updated (updated)

 

설명: 데이터가 변경되어 DOM이 다시 렌더링된 후 호출됩니다.

용도: 데이터 변경에 따른 DOM 작업을 수행할 수 있습니다.

updated() {
  console.log('updated: 데이터가 변경되고 DOM이 업데이트되었습니다.');
}

7) Before Destroy (beforeDestroy)

 

설명: Vue 인스턴스가 파괴되기 전에 호출됩니다.

용도: 인스턴스가 파괴되기 전에 정리 작업을 수행할 수 있습니다. 이벤트 리스너 해제, 타이머 제거 등이 필요할 때 사용합니다.

beforeDestroy() {
  console.log('beforeDestroy: 인스턴스가 파괴되기 전입니다.');
}

8) Destroyed (destroyed)

 

설명: Vue 인스턴스가 파괴된 후 호출됩니다. 인스턴스의 모든 바인딩과 이벤트 리스너가 해제됩니다.

용도: 인스턴스 파괴 후의 작업을 수행할 수 있습니다.

destroyed() {
  console.log('destroyed: 인스턴스가 파괴되었습니다.');
}

2. Vue 3에서의 Composition API 생성주기

 

Vue 3에서는 Composition API가 도입되면서 라이프사이클 훅도 setup 함수 내에서 사용할 수 있도록 변경되었습니다. 각 훅은 Vue 2의 Options API에서와 동일한 시점에 호출되지만, 이름이 조금씩 다릅니다.

 

onBeforeMount: beforeMount와 동일한 타이밍에 호출됩니다.

onMounted: mounted와 동일한 타이밍에 호출됩니다.

onBeforeUpdate: beforeUpdate와 동일한 타이밍에 호출됩니다.

onUpdated: updated와 동일한 타이밍에 호출됩니다.

onBeforeUnmount: beforeDestroy와 동일한 타이밍에 호출됩니다.

onUnmounted: destroyed와 동일한 타이밍에 호출됩니다.

 

import { onMounted, onBeforeUnmount } from 'vue';

export default {
  setup() {
    onMounted(() => {
      console.log('mounted: 컴포넌트가 마운트되었습니다.');
    });

    onBeforeUnmount(() => {
      console.log('beforeUnmount: 컴포넌트가 파괴되기 전입니다.');
    });
  }
};

3. 생성주기 훅의 활용 예시

 

API 호출

 

created 또는 onMounted에서 초기 데이터를 가져오기 위해 API를 호출할 수 있습니다.

created() {
  fetch('/api/data')
    .then(response => response.json())
    .then(data => {
      this.data = data;
    });
}

// Composition API 방식
onMounted(() => {
  fetch('/api/data')
    .then(response => response.json())
    .then(data => {
      state.data = data;
    });
});

DOM 초기화

 

외부 라이브러리나 플러그인을 초기화하기 위해 mountedonMounted를 사용할 수 있습니다.

mounted() {
  this.$nextTick(() => {
    this.initializePlugin();
  });
}

// Composition API 방식
onMounted(() => {
  nextTick(() => {
    initializePlugin();
  });
});

4. 결론

 

Vue의 생명주기는 컴포넌트의 생성, 렌더링, 업데이트, 파괴 과정에서 특정 시점에 코드 실행을 가능하게 합니다. Options API에서는 메서드 형태로 각 훅을 정의하며, Composition API에서는 setup 함수 내부에서 훅을 호출하는 방식으로 관리합니다. 이 생성주기 훅들은 컴포넌트의 초기화, DOM 접근, 외부 자원 관리, 데이터 업데이트 등에 중요한 역할을 합니다.


생성주기 문서

https://ko.vuejs.org/guide/essentials/lifecycle.html

반응형

'프론트엔드 > Vuejs' 카테고리의 다른 글

vue to-do 리스트 구현 7 - composition api 비교  (0) 2024.08.18
Vuetify 문서 레퍼런스 가이드  (0) 2024.08.17
vue vuex 란  (0) 2024.08.17
vue to-do 리스트 구현 6 - vuex 구현  (0) 2024.08.17
Vue Router란?  (0) 2024.08.17
반응형

 

1. Option API와 Composition API 비교 설명

 

Option API:

전통적인 Vue.js 방식으로, 컴포넌트의 로직을 data, methods, computed, watch 등으로 구분합니다.

코드의 구조가 명확하게 나누어져 있어, 이해하기 쉬운 것이 장점입니다.

큰 컴포넌트에서는 로직이 흩어져 있어 관리가 어려워질 수 있습니다.

Composition API:

Vue 3에서 도입된 새로운 방식으로, 함수형 프로그래밍 스타일에 가까운 접근법입니다.

관련 로직을 setup 함수 내에서 함께 정의할 수 있어, 큰 컴포넌트에서도 관련 로직을 그룹화하여 관리할 수 있습니다.

ref, computed, watch, onMounted 등의 기능을 활용하여 상태와 라이프사이클을 관리합니다.

코드 재사용성이 높아지며, 특히 큰 프로젝트에서 유리합니다.

 

Composition API를 사용하여 post 게시판을 구현하면서 기존의 Option API 방식과 비교할 수 있었습니다. Composition API는 보다 유연하고 코드 재사용성을 높이는 데 유리하며, Vuex와의 결합도 자연스럽습니다. 이를 통해 학생들이 Vue의 두 가지 API 스타일을 이해하고, 필요에 따라 적절히 선택할 수 있도록 도울 수 있습니다.

todoList 를 postList 로 동일한 코드로 composition api 로 변형 해보았습니다. 


PostList.vue

<template>
    <v-container>
      <v-row>
        <v-col>
          <h1>Vue.js Post Board</h1>
          <AddPost @add-post="addPost" />
          <v-list>
            <v-list-item
              v-for="(post, index) in posts"
              :key="index"
              @click="navigateToDetail(index)"
            >
              <template v-slot:prepend>
                <v-checkbox
                  v-model="post.completed"
                  @click.stop="togglePostStatus(index, !post.completed)"
                  hide-details
                />
              </template>
              
              <v-list-item-title>{{ post.text }}</v-list-item-title>
              
              <template v-slot:append>
                <v-btn icon="mdi-delete" size="small" @click.stop="removePost(index)">
                </v-btn>
              </template>
            </v-list-item>
          </v-list>
        </v-col>
      </v-row>
    </v-container>
  </template>
  
  <script>
  import { computed, onMounted } from 'vue';
  import { useRouter } from 'vue-router';  // useRouter를 import
  import { useStore } from 'vuex';
  import AddPost from './AddPost.vue';
  
  export default {
    name: 'PostList',
    components: { AddPost },
    setup() {
      const store = useStore();
      const router = useRouter();
  
      const posts = computed(() => store.getters.posts);
      const addPost = (postText) => store.dispatch('addPost', postText);
      const removePost = (index) => store.dispatch('removePost', index);
      const togglePostStatus = (index, completed) =>
        store.dispatch('togglePostStatus', { index, completed });
  
      const navigateToDetail = (index) => {
        // Navigate to post detail page
        router.push({ name: 'PostDetail', params: { id: index } });
      };
  
      onMounted(() => {
        store.dispatch('loadPosts');
      });
  
      return {
        posts,
        addPost,
        removePost,
        togglePostStatus,
        navigateToDetail,
      };
    },
  };
  </script>

 

AddPost.vue

<template>
    <v-text-field
      v-model="newPost"
      label="Add a new post"
      @keyup.enter="submitPost"
      outlined
      dense
    />
    <v-btn color="primary" @click="submitPost">Add</v-btn>
  </template>
  
  <script>
  import { ref } from 'vue';
  
  export default {
    name: 'AddPost',
    emits: ['add-post'],  // 커스텀 이벤트를 정의합니다.
    setup(props, { emit }) {
      const newPost = ref('');
  
      const submitPost = () => {
        if (newPost.value.trim()) {
          emit('add-post', newPost.value);
          newPost.value = '';
        }
      };
  
      return {
        newPost,
        submitPost,
      };
    },
  };
  </script>

 

PostDetail.vue

<template>
    <v-container>
      <h2>Post Detail</h2>
      <v-card>
        <v-card-text>
          <p>ID: {{ id }}</p>
          <p v-if="post">Text: {{ post.text }}</p>
          <p v-else>Post not found</p>
        </v-card-text>
      </v-card>
      <v-btn @click="$router.push('/post')">Back</v-btn>
    </v-container>
  </template>
  
  <script>
  import { computed } from 'vue';
  import { useStore } from 'vuex';
  import { useRoute } from 'vue-router';
  
  export default {
    setup() {
      const store = useStore();
      const route = useRoute();
  
      const id = computed(() => route.params.id);
      const post = computed(() => store.getters['posts'][id.value]);
  
      return {
        id,
        post,
      };
    },
  };
  </script>

 

 

이전에 만들었던 todo List 와 비교하면서 보면 이해가 빠를 겁니다. 



2. Composition API 구성 요소

 

1) setup 함수

 

setup 함수는 Composition API의 핵심으로, 컴포넌트가 생성될 때 호출됩니다. 이 함수 내에서 상태 관리, 메서드 정의, 라이프사이클 훅 등을 설정할 수 있습니다.

 

리턴값: setup 함수에서 반환하는 객체는 템플릿에서 사용됩니다. 이 함수에서 정의한 모든 데이터와 메서드는 setup의 반환 객체를 통해 템플릿에서 접근 가능합니다.

 

2) useStore와 useRouter

 

useStore: Vuex의 스토어에 접근하기 위해 사용됩니다. store 객체를 반환하며, 이를 통해 상태 관리와 관련된 모든 작업을 수행할 수 있습니다.

useRouter: Vue Router에서 제공하는 훅으로, 현재 라우터 인스턴스에 접근하여 라우팅을 처리할 수 있습니다. 예를 들어, 페이지 이동을 위해 router.push를 사용할 수 있습니다.

 

3) computed

 

computed 속성은 반응형 데이터를 정의할 때 사용됩니다. 여기서 posts는 Vuex 스토어에서 가져온 할 일 목록으로, computed로 선언하여 Vue의 반응형 시스템과 연결됩니다.

 

4) onMounted

 

onMounted는 Vue의 라이프사이클 훅 중 하나로, 컴포넌트가 DOM에 마운트된 직후 호출됩니다. 이 훅을 사용하여 컴포넌트가 초기화될 때 필요한 작업을 수행할 수 있습니다. 예를 들어, 이 코드에서는 컴포넌트가 마운트될 때 loadPosts 액션을 디스패치하여 로컬 스토리지에서 데이터를 불러옵니다.

3. 구현된 기능 설명

 

Post 목록 가져오기 (posts): posts는 Vuex의 getters.postscomputed로 받아와, 템플릿에서 렌더링됩니다.

Post 추가하기 (addPost): 사용자가 새로운 포스트를 추가하면, 해당 텍스트가 Vuex 액션을 통해 posts 상태에 추가됩니다.

Post 상태 토글 (togglePostStatus): 체크박스를 클릭하여 포스트의 완료 상태를 토글할 수 있습니다. 이 상태는 v-modelstore.dispatch를 통해 Vuex와 동기화됩니다.

Post 삭제하기 (removePost): 삭제 버튼을 클릭하면 해당 포스트가 삭제됩니다. 이 작업 역시 Vuex 액션을 통해 처리됩니다.

Post 상세보기 페이지로 이동 (navigateToDetail): 포스트 항목을 클릭하면 해당 포스트의 상세 페이지로 라우팅됩니다. router.push를 통해 PostDetail 페이지로 이동하며, id 파라미터를 전달합니다.

 

4. Composition API와 Options API 비교

 

유연성: Composition API는 로직과 상태 관리를 한 곳에 모아서 정의할 수 있으므로, 관련된 코드를 쉽게 그룹화하고 재사용할 수 있습니다.

재사용성: Composition API는 함수로 로직을 캡슐화하여 재사용할 수 있어, 복잡한 컴포넌트에서 더 나은 코드 조직화를 제공합니다.

명확성: setup 함수 안에서 모든 로직을 관리하므로, 상태와 메서드가 어디에서 정의되고 어떻게 사용되는지 명확히 알 수 있습니다.


이전 블로그 
vuex 를 이용한 todo list 작성
https://juntcom.tistory.com/323 

 

vue 가이드 - option, composition api 
https://ko.vuejs.org/guide/introduction.html

 

반응형

'프론트엔드 > Vuejs' 카테고리의 다른 글

vue lifecycle 라이프사이클 정리  (0) 2024.08.18
Vuetify 문서 레퍼런스 가이드  (0) 2024.08.17
vue vuex 란  (0) 2024.08.17
vue to-do 리스트 구현 6 - vuex 구현  (0) 2024.08.17
Vue Router란?  (0) 2024.08.17
반응형

Vuetify는 Material Design 가이드를 따르는 Vue.js UI 라이브러리로, 다양한 사전 제작된 컴포넌트와 유틸리티를 제공하여 반응형이고 미적으로 우수한 인터페이스를 빠르게 개발할 수 있도록 도와줍니다. 아래는 Vuetify를 효과적으로 사용하는 데 필요한 주요 개념과 문서에 대한 가이드입니다.

 

Vuetify 시작하기

 

설치

공식 설치 가이드: Vuetify 설치

vue add vuetify

 

npm install vuetify

 

설치 후 main.js 파일에서 Vuetify를 설정합니다:

import { createApp } from 'vue';
import App from './App.vue';
import vuetify from './plugins/vuetify';

createApp(App)
  .use(vuetify)
  .mount('#app');

 

스타일링 및 레이아웃

Vuetify는 Material Design의 레이아웃 시스템을 따릅니다. v-container, v-row, v-col을 사용하여 반응형 레이아웃을 쉽게 구성할 수 있습니다.

 

v-container: 레이아웃의 기본 컨테이너로, 내부에 v-rowv-col을 포함합니다.

v-row: 수평 행을 생성하며, 여러 v-col을 포함할 수 있습니다.

v-col: 열을 생성하며, 그리드 시스템에서 비율에 따라 폭을 차지합니다.

<v-container>
  <v-row>
    <v-col cols="12" md="8">Main content</v-col>
    <v-col cols="12" md="4">Sidebar</v-col>
  </v-row>
</v-container>

 

 

텍스트 크기 및 타이포그래피

 

Vuetify는 text-h1에서 text-h6까지 다양한 텍스트 스타일과 크기를 제공하며, 이러한 클래스들을 사용해 쉽게 텍스트 스타일을 적용할 수 있습니다.

문서: 텍스트 및 타이포그래피

<v-typography variant="h1">This is a headline</v-typography>
<v-typography variant="body-1">This is body text</v-typography>

 

컬러 팔레트

 

Vuetify는 Material Design을 기반으로 한 색상 팔레트를 포함하고 있어, 애플리케이션 전반에 걸쳐 일관된 색상 테마를 쉽게 적용할 수 있습니다.

문서: Material Colors

 

아이콘 폰트

 

Vuetify는 다양한 아이콘 폰트를 지원하며, Material Design Icons(MDI)와 쉽게 통합할 수 있습니다.

아이콘 검색 및 사용: Vuetify 아이콘 폰트

MDI 전체 라이브러리 보기: MDI 아이콘 라이브러리

 

테마 커스터마이징

 

Vuetify에서 애플리케이션의 테마를 커스터마이징할 수 있습니다. 테마 값은 myCustomLightTheme 객체를 수정하여 변경할 수 있습니다.

문서: 테마 설정

const vuetify = createVuetify({
  theme: {
    themes: {
      light: {
        primary: '#3f51b5',
        secondary: '#b0bec5',
        accent: '#8c9eff',
        error: '#b71c1c',
      },
    },
  },
});

 

 

컬러 속성

 

Vuetify의 컬러 속성을 사용하여 Material Design의 색상 시스템으로 컴포넌트를 스타일링할 수 있습니다.

문서: 컬러 속성

 

간격(Spacing) 유틸리티

 

Vuetify는 마진과 패딩을 쉽게 관리할 수 있는 간격 유틸리티를 제공합니다.

문서: 간격 유틸리티

 

그리드 시스템 (Col 속성)

 

Vuetify의 그리드 시스템은 Flexbox를 기반으로 하며, 강력한 레이아웃 시스템을 제공합니다.

문서: 그리드 및 Col 속성

 

컴포넌트

 

텍스트 필드

 

텍스트 필드는 사용자로부터 텍스트 입력을 받기 위한 주요 폼 요소입니다.

문서: 텍스트 필드

<v-form>
  <v-text-field label="Name" v-model="name"></v-text-field>
  <v-select :items="['Option 1', 'Option 2']" label="Select an option"></v-select>
  <v-checkbox label="Accept Terms" v-model="accepted"></v-checkbox>
</v-form>

 

 

라디오 버튼

 

라디오 버튼은 목록에서 하나의 옵션을 선택할 때 사용됩니다.

문서: 라디오 버튼

 

다이얼로그(Dialog)

 

다이얼로그는 중요한 정보나 사용자의 결정을 요청하는 모달 창입니다.

예시: 다이얼로그 사용법

<v-dialog v-model="dialog">
  <v-card>
    <v-card-title>Dialog Title</v-card-title>
    <v-card-text>
      This is a dialog content.
    </v-card-text>
    <v-card-actions>
      <v-btn @click="dialog = false">Close</v-btn>
    </v-card-actions>
  </v-card>
</v-dialog>

 

 

데이터 테이블

 

데이터 테이블은 구조화된 데이터를 표 형식으로 표시하는 데 사용되며, 정렬, 페이징, 검색 등의 기능을 제공합니다.

문서: 데이터 테이블

<v-data-table :headers="headers" :items="items" :search="search">
  <template v-slot:top>
    <v-text-field v-model="search" label="Search"></v-text-field>
  </template>
</v-data-table>

 

카드

 

카드는 다양한 유형의 콘텐츠를 표시하는 데 유용한 유연한 컨테이너입니다.

예시: 카드 사용법

<v-card>
  <v-card-title>Card Title</v-card-title>
  <v-card-subtitle>Card Subtitle</v-card-subtitle>
  <v-card-text>
    This is some text within a card.
  </v-card-text>
  <v-card-actions>
    <v-btn text>Action</v-btn>
  </v-card-actions>
</v-card>

 

 

셀렉트 입력

 

셀렉트 입력은 목록에서 옵션을 선택할 수 있도록 합니다.

문서: 셀렉트 입력

 

내비게이션 드로어

 

내비게이션 드로어는 사이드 메뉴를 제공하며, 토글로 표시하거나 숨길 수 있습니다.

문서: 내비게이션 드로어

 

리스트

 

리스트는 관련된 콘텐츠를 그룹화하여 표시하는 데 사용됩니다.

문서: 리스트

 

 

칩은 복잡한 엔티티를 컴팩트한 형태로 표현하는 작은 컴포넌트입니다.

예시: 칩 사용법

API 문서: v-chip API

 

반응형

'프론트엔드 > Vuejs' 카테고리의 다른 글

vue lifecycle 라이프사이클 정리  (0) 2024.08.18
vue to-do 리스트 구현 7 - composition api 비교  (0) 2024.08.18
vue vuex 란  (0) 2024.08.17
vue to-do 리스트 구현 6 - vuex 구현  (0) 2024.08.17
Vue Router란?  (0) 2024.08.17
반응형

Vuex는 Vue.js 애플리케이션에서 상태 관리를 중앙 집중화할 수 있도록 도와주는 공식적인 상태 관리 패턴 및 라이브러리입니다.

Vuex를 사용하면 애플리케이션의 상태를 중앙에서 관리하고, 이를 다양한 컴포넌트들이 공유할 수 있습니다.

Vuex는 특히 규모가 큰 애플리케이션에서 컴포넌트 간의 상태 관리를 단순화하고, 일관된 상태 관리를 가능하게 합니다.

 

Vuex의 주요 개념

 

1. State (상태)

state는 애플리케이션의 중앙에서 관리되는 상태를 정의합니다. Vue 컴포넌트의 data와 유사하지만, 여러 컴포넌트가 공유할 수 있는 중앙 집중식 상태입니다.

const store = createStore({
  state: {
    todos: []
  },
});

2. Mutations (변이)

mutations는 상태를 변경하는 메서드입니다. 상태를 변경할 때는 반드시 mutations를 통해 변경해야 합니다. 이는 Vuex의 핵심 개념 중 하나로, 상태 변이를 추적하고 디버깅을 쉽게 만들어줍니다.

mutations: {
  setTodos(state, todos) {
    state.todos = todos;
  },
  addTodo(state, todo) {
    state.todos.push(todo);
  },
  removeTodo(state, index) {
    state.todos.splice(index, 1);
  },
  updateTodoStatus(state, { index, completed }) {
    state.todos[index].completed = completed;
  }
}

3. Actions (액션)

actionsmutations와 유사하지만, 비동기 작업을 처리할 수 있습니다. 액션은 mutations를 커밋하여 상태를 변경합니다. 예를 들어, API 호출 후 응답 데이터를 상태에 반영하는 작업을 actions에서 처리합니다.

 

actions: {
  loadTodos({ commit }) {
    const savedTodos = localStorage.getItem('todos');
    if (savedTodos) {
      commit('setTodos', JSON.parse(savedTodos));
    }
  },
  saveTodos({ state }) {
    localStorage.setItem('todos', JSON.stringify(state.todos));
  },
  addTodo({ commit, dispatch }, todoText) {
    const newTodo = { text: todoText, completed: false };
    commit('addTodo', newTodo);
    dispatch('saveTodos');
  },
  removeTodo({ commit, dispatch }, index) {
    commit('removeTodo', index);
    dispatch('saveTodos');
  },
  toggleTodoStatus({ commit, dispatch }, payload) {
    commit('updateTodoStatus', payload);
    dispatch('saveTodos');
  }
}

 

4. Getters (게터)

getters는 상태에서 값을 가져올 때 사용됩니다. Vue 컴포넌트에서 computed 속성과 유사하게 동작합니다. 상태를 가공하거나 필터링하여 반환할 수 있습니다.

getters: {
  todos(state) {
    return state.todos;
  }
}

5. Store (스토어)

Vuex store는 Vuex의 중심입니다. 상태(state), 변이(mutations), 액션(actions), 게터(getters) 등을 포함하여 애플리케이션의 전체 상태를 관리합니다. 컴포넌트는 이 스토어를 통해 중앙 상태에 접근하고, 변경할 수 있습니다.

import { createStore } from 'vuex';

const store = createStore({
  state: {
    todos: []
  },
  mutations: { /* 변이들 */ },
  actions: { /* 액션들 */ },
  getters: { /* 게터들 */ }
});

export default store;

 

 

 

 

 

 

Vuex의 사용 예시

 

다음은 Vuex를 활용하여 To-Do 리스트 애플리케이션의 상태를 관리하는 방법에 대한 예시입니다.

 

1. 상태 정의 및 초기화

todos 배열을 상태로 정의하고, 로컬 스토리지에서 저장된 할 일 목록을 불러와 todos에 저장합니다.

state: {
  todos: []
}

2. 상태 업데이트

사용자가 새로운 할 일을 추가하거나, 할 일의 상태를 변경하면 Vuex의 mutations를 통해 상태가 업데이트됩니다.

mutations: {
  addTodo(state, todo) {
    state.todos.push(todo);
  },
  updateTodoStatus(state, { index, completed }) {
    state.todos[index].completed = completed;
  }
}

3. 액션을 통한 상태 관리

actions를 통해 비동기 작업과 상태 변이를 처리합니다. 예를 들어, 로컬 스토리지에 할 일 목록을 저장하는 작업은 actions에서 처리됩니다.

actions: {
  saveTodos({ state }) {
    localStorage.setItem('todos', JSON.stringify(state.todos));
  }
}

4. 컴포넌트에서 Vuex 상태 접근

컴포넌트에서는 mapGetters, mapActions를 사용하여 Vuex 상태와 메서드를 간단히 연결할 수 있습니다.

<script>
import { mapGetters, mapActions } from 'vuex';

export default {
  computed: {
    ...mapGetters(['todos'])
  },
  methods: {
    ...mapActions(['addTodo', 'toggleTodoStatus', 'removeTodo'])
  }
}
</script>

요약

 

중앙 집중화된 상태 관리: Vuex를 사용하면 상태를 중앙에서 관리하여 컴포넌트 간의 상태 공유와 변경을 쉽게 추적할 수 있습니다.

예측 가능한 상태 관리: 모든 상태 변경은 mutations를 통해 이루어지므로, 상태 변경을 쉽게 예측하고 디버깅할 수 있습니다.

비동기 작업 관리: 비동기 작업은 actions를 통해 관리되어, 복잡한 비동기 로직도 쉽게 처리할 수 있습니다.

Vue 컴포넌트와의 통합: mapGettersmapActions를 통해 Vue 컴포넌트와 Vuex 상태 및 메서드를 간단히 연결할 수 있습니다.

 

Vuex는 규모가 큰 애플리케이션에서 특히 유용하며, 상태를 일관되게 유지하고 컴포넌트 간의 상태 관리 복잡성을 줄여줍니다.

반응형
반응형

Vuex를 사용하여 To-Do 리스트 애플리케이션을 리팩토링하는 방법을 설명하겠습니다.

Vuex는 Vue.js 애플리케이션에서 상태 관리를 중앙에서 처리할 수 있도록 도와주는 라이브러리입니다.

이 예제에서는 Vuex를 사용하여 할 일 목록(todos)을 중앙에서 관리하고, 컴포넌트들이 Vuex 스토어를 통해 상태를 접근하고 수정하도록 하겠습니다.

 

1. Vuex 설치

 

먼저 Vuex를 설치해야 합니다.

npm install vuex@next

2. Vuex 스토어 설정 (store/index.js)

 

src/store/index.js 파일을 생성하고, Vuex 스토어를 설정합니다.

import { createStore } from 'vuex'

const store = createStore({
  state: {
    todos: []
  },
  mutations: {
    setTodos(state, todos) {
      state.todos = todos;
    },
    addTodo(state, todo) {
      state.todos.push(todo);
    },
    removeTodo(state, index) {
      if (index >= 0 && index < state.todos.length) {
        state.todos.splice(index, 1);
      }
    },
    updateTodoStatus(state, { index, completed }) {
      if (index >= 0 && index < state.todos.length) {
        state.todos[index].completed = completed;
      }
    }
  },
  actions: {
    loadTodos({ commit }) {
      const savedTodos = localStorage.getItem('todos');
      if (savedTodos) {
        commit('setTodos', JSON.parse(savedTodos));
      }
    },
    saveTodos({ state }) {
      localStorage.setItem('todos', JSON.stringify(state.todos));
    },
    addTodo({ commit, dispatch }, todoText) {
      const newTodo = { text: todoText, completed: false };
      commit('addTodo', newTodo);
      dispatch('saveTodos');
    },
    removeTodo({ commit, dispatch }, index) {
      commit('removeTodo', index);
      dispatch('saveTodos');
    },
    toggleTodoStatus({ commit, dispatch }, payload) {
      const { index, completed } = payload;
      console.log('toggleTodoStatus', index, completed);
      commit('updateTodoStatus', { index, completed });
      dispatch('saveTodos');
    }
  },
  getters: {
    todos(state) {
      return state.todos;
    }
  }
});

export default store;

3. Vue 애플리케이션에 Vuex 추가 (main.js)

 

main.js 파일에서 Vuex 스토어를 Vue 애플리케이션에 추가합니다.

import { createApp } from 'vue'
import App from './App.vue'
import vuetify from './plugins/vuetify'
import { loadFonts } from './plugins/webfontloader'
import router from './router'  // Vue Router를 추가
import store from './store'  // Vuex 스토어를 가져옵니다.


loadFonts()

createApp(App)
  .use(vuetify)
  .use(router)  // Vue Router 사용
  .use(store)  // Vuex 스토어를 사용합니다.
  .mount('#app')

4. ToDoList.vue 컴포넌트 수정

 

이제 ToDoList.vue 컴포넌트를 수정하여 Vuex 스토어에서 상태를 가져오고, 할 일을 추가 및 삭제하는 기능을 구현합니다.

<template>
  <v-container>
    <v-row>
      <v-col>
        <h1>Vue.js To-Do App</h1>
        <AddTodo @add-todo="addTodo" />
        <v-list>
          <v-list-item
            v-for="(todo, index) in todos"
            :key="index"
            @click="$router.push({ name: 'ToDoDetail', params: { id: index } })"
          >
            <template v-slot:prepend>
              <v-checkbox
                v-model="todo.completed"
                @click.stop="toggleTodoStatus({ index, completed: !todo.completed })"
                hide-details
              />
            </template>
            
            <v-list-item-title>{{ todo.text }}</v-list-item-title>
            
            <template v-slot:append>
              <v-btn icon="mdi-delete" size="small" @click.stop="removeTodo(index)">
              </v-btn>
            </template>
          </v-list-item>
        </v-list>
      </v-col>
    </v-row>
  </v-container>
</template>

<script>
import AddTodo from './AddTodo.vue'
import { mapActions, mapGetters } from 'vuex'

export default {
  name: 'ToDoList',
  components: { AddTodo },
  computed: {
    ...mapGetters(['todos'])  // Vuex에서 todos 상태를 가져옵니다.
  },
  methods: {
    ...mapActions(['addTodo', 'removeTodo', 'toggleTodoStatus']),  // Vuex 액션들을 가져옵니다.
  },
  created() {
    this.$store.dispatch('loadTodos')  // Vuex 스토어에서 할 일을 로드합니다.
  }
}
</script>

5. TodoDetail.vue 컴포넌트 수정

 

TodoDetail.vue에서 Vuex 상태를 사용하도록 수정합니다.

<template>
    <v-container>
      <h2>To-Do Detail</h2>
      <v-card>
        <v-card-text>
          <p>ID: {{ id }}</p>
          <p v-if="todo">Text: {{ todo.text }}</p>
          <p v-else>Todo not found</p>
        </v-card-text>
      </v-card>
      <v-btn @click="$router.push('/')">Back</v-btn>
    </v-container>
  </template>
  
  <script>
  import { mapGetters } from 'vuex'
  
  export default {
    props: {
      id: {
        type: String,
        required: true
      }
    },
    computed: {
      ...mapGetters(['todos']),
      todo() {
        return this.todos[this.id]
      }
    }
  }
  </script>

 

1. Vuex 상태 관리:

state: todos 배열을 중앙에서 관리합니다.

mutations: 상태를 직접적으로 변경하는 로직을 포함합니다(addTodo, removeTodo, updateTodoStatus).

actions: 비동기 작업이나 여러 변형을 처리하고, 상태를 변경하는 메서드를 포함합니다(loadTodos, saveTodos 등).

2. ToDoList.vue 컴포넌트:

computed: mapGetters를 통해 Vuex에서 todos 상태를 가져옵니다.

methods: mapActions를 통해 Vuex 액션을 사용하여 할 일을 추가, 삭제, 상태를 변경하고, 로컬 스토리지와 동기화합니다.

created: 컴포넌트가 생성될 때 loadTodos 액션을 호출하여 로컬 스토리지에서 저장된 할 일 목록을 불러옵니다.


이전 블로그

vue to-do 리스트 구현 5 - router 구현

https://juntcom.tistory.com/321 

반응형

'프론트엔드 > Vuejs' 카테고리의 다른 글

Vuetify 문서 레퍼런스 가이드  (0) 2024.08.17
vue vuex 란  (0) 2024.08.17
Vue Router란?  (0) 2024.08.17
vue to-do 리스트 구현 5 - router 구현  (0) 2024.08.17
vue to-do 리스트 구현 4 - vuetify 적용  (0) 2024.08.16

+ Recent posts