NEW
1
/ 5
[3] 타입스크립트 선택적 타입을 통해 누락된 값이 있어도 타입 추론을 해보기
개요여러가지를 통해 api로 값을 받아올때면 일부 값은 누락되어 오는 경우가 허다하게 발생하는데,이번에는 타입스크립트의 선택적 타입 정의를 통해 특정 값이 누락되어도 타입 정의를 통해 추론이 잘 이루어질 수 있게끔 해보겠습니다!선택적 타입 정의?타입을 정의하게 되면 해당 타입과 관련된 값이 꼭 존재해야하는 불편함이 있는데선택적 타입 정의를 사용하게 되면 값의 존재 유무에 따라 타입을 검사해주는 고마운 친구였습니다 ㅎ사용방법코드보기export type UserCardProps = { name: string; age?: number; // 선택적 props skills?: string[]; // 선택적 배열 props}선택적 타입 정의를 위해서는 원하시는 값에다가 ?를 뒤에 붙여주시면 됩니다.그럼 아래와 같은 상황에서 age가 없으면 타입 추론을 안하게 되며,age 존재시 age의 타입이 number인지 추론을 하게 됩니다.코드보기export const UserCard = ({ name, age, skills = [], address }: UserCardProps) => {}마치며알면 알수록 편리하고 다양한 기능이 타입스크립트에 있는거 같네요정말 스크립트의 세계는 방대하네요...
NEW
2
/ 5
클로저란 무엇일까
사진: Unsplash의 Mārtiņš Zemlickis개요사실상 면접을 대비한 공부라고 할수도 있고일상생활에 있다보니 그러려니 하고 쓰다가 명칭을 알게된 경우였는데이번 기회에 클로저에 대해 알기쉽게 이해해보고자 작성하게 되었습니다.클로저란?쉽게 얘기하면 클로저란 함수 자체에 독자적인 변수가 존재하고 이걸 콜백함수로 제어가 가능해야 하며 이 함수를 변수에 담아 호출해야 합니다,스코프(변수의 범위)가 함수와 그 함수가 선언될 당시의 스코프를 기억하는 구조로,이를 통해 함수가 외부 스코프의 변수에 접근할 수 있도록 해줍니다.조건은 뭘까?1.내부 함수가 존재해야 합니다.2.이 내부 함수가 외부 변수에 접근하고 있어야 합니다.3.이 내부 함수가 반환되어 외부에서 호출될 수 있어야 합니다.특성은 뭐가 있을까?변수 접근: 클로저를 통해 내부 함수는 외부 함수의 변수를 계속해서 참조할 수 있어서 이로 인해 외부 함수가 실행된 후에도 변수의 값을 사용할 수 있게 됩니다.정보 은닉: 클로저를 사용하면 특정 변수를 외부에서 직접 접근하지 못하도록 숨길 수 있어서 이렇게 하면 데이터의 캡슐화가 이루어지고, 해당 데이터에 대한 제어가 가능해집니다.상태 유지: 클로저를 통해 생성된 내부 함수는 외부 변수의 상태를 기억하고, 이 상태를 변화시킬 수 있어서 그래서 특정 기능을 구현할 때 유용하게 사용됩니다.예시클로저를 생성하는법const counter = makeCounter();클로저의 핵심은 함수를 호출했을때 그 결과가 콜백함수여야 한다는 것입니다.그래야 함수 속 외부 변수를 이용해 콜백함수로 그 외부변수에 값을 변화 시킬 수 있겠죠?쉬운 예제const makeCounter = () => { let like = 0; // 외부 변수 return () => { // 콜백 함수 = 클로저 return like += 1; };};// 클로저 생성const counter = makeCounter();ㅊconsole.log(counter()); // like 변수의 값 반환 1console.log(counter()); // like 변수의 값 반환 2console.log로 makeCounter가 호출될때마다 like += 1 를 반환해주고 있기 때문에,해당 변수의 반환된 값이 counter 상수에 저장되어 사용되어집니다.비스무리한 다른 예제function makeCounter() { let count = 0; // 외부 변수 return function() { count += 1; // 외부 변수를 변경 return count; // 변경된 외부 변수를 반환 };}const counter = makeCounter(); // 클로저 생성console.log(counter()); // 1console.log(counter()); // 2console.log(counter()); // 3makeCounter 함수에는 독자적인 count라는 변수가 있고그 외부 변수를 제어 하고 반환하는 콜백함수를 리턴하고 있으며makeCounter 함수를 counter라는 상수에 담아console.log로 호출해 사용하고 있습니다.클로저가 아닌 경우다음과 같은 경우는 클로저가 아닙니다.let count = 0;const increment = () => { count += 1; // 외부 변수에 접근하지만, 반환되는 것이 없음};increment(); // 단순히 호출만 됨단순히 외부 변수를 접근해 변화시키고만 있지increment함수 자체가 변수를 기억하고 반환되는것이 아니기 때문에 클로저라 할 수 없습니다.
NEW
3
/ 5
[2] 타입스크립트의 타입 정의 상속에 대하여
사진: Unsplash의 Markus Spiske개요저번에는 타입을 어떻게 정의하고 사용하는지에 대해 알아봤는데이번에는 상속을 이용해서 타입을 조합해 정의해보겠습니다!타입 정의 방법type Test = { name: string, // 이름 description: string, // 설명 age: number, // 나이 func: () => void // 함수}테스트로 타입을 정의 해보았습니다.이 부분이 저번에 알려드린 내용과 같은데요.하지만 이렇게 사용하게 되면 특수한 상황,예를 들면 name과 age의 타입만 필요한 상황, func와 name의 타입 정의만 필요한 상황 같은 특수한 상황이 있을 수 있는데요이럴때 필요한게 상속입니다.상속이란?마치 레고를 조립하듯이 기본이 되는 기본 블럭이 있고거기에 특수한 기능을 가진 블럭을 붙이는 겁니다.예시// 형태type Shape = { style: string // 스타일 color: string // 색상}// 상세정보type Details = { name: string, // 이름 description: string, // 설명 date: number // 날짜}// 자동차 베이스type Car = { company: string, // 이름 country: string // 설명}만약 이러한 값이 있다고 하였을때자동차 베이스에 형태 + 상세정보를 합쳐야 하는 상황이 있는데지금과 같은 경우엔 나뉘어져 있어 조립이 필요한 상황입니다.이 경우 다음과 같이 하면 됩니다.// 형태interface Shape { style: string; // 스타일 color: string; // 색상}// 상세정보interface Details extends Shape { name: string; // 이름 description: string; // 설명 date: number; // 날짜}// 자동차 베이스interface Car extends Details { company: string; // 이름 country: string; // 설명}결과이렇게 할 경우 Car 타입을 사용하면 이런 형태를 지니게 됩니다.const myCar: Car = { style: "SUV", color: "red", name: "My Car", description: "This is a great car!", date: 2024, company: "Toyota", country: "Japan"};상속의 방법상속의 방법은 interface의 extends만 있는게 아닌데요 type에 &를 붙여 조합하는것 또한 가능합니다.그럼 결국 둘은 똑같은게 아니냐는 생각이 들수도 있을텐데비유로 다름을 설명해보자면const(상수)는 재선언 재할당이 불가능합니다.var(변수)는 재선언 재할당이 가능합니다.extends와 &는 이 차이인겁니다.interface의 extends는 재선언 재할당이 불가능합니다.type의 &는 재선언 재할당이 가능합니다.예시interface의 경우interface User { name: string;}interface User { age: number; // 병합됨}const user: User = { name: "CODi", age: 28,};type의 경우type User = { name: string;};type User = { // 오류 발생 age: number;};마무리이번에는 타입의 상속에 대해 알아보았습니다.그래도 블럭으로 비유하며 생각해보니 상속이라고 외우는것보다 더 쉽네요 ㅋㅋㅋ
NEW
4
/ 5
FSD 구조를 통해 프로젝트의 폴더 구조를 명확히 해보자
사진: Unsplash의 Leiada Krozjhen개요항상 토이프로젝트를 만들다 보면 문득 고민에 빠지는 것들이 있었습니다.공용 컴포넌트의 경우, 이 컴포넌트는 여러 곳에서 사용되지만, 모든 곳에서 쓰지는 않습니다. 과연 여기 위치해도 괜찮은 것일까요?전역 사용 컴포넌트의 경우, 이 컴포넌트는 모든 곳에서 사용되긴 하는데, 하나의 컴포넌트 때문에 공용으로 사용하는 폴더에 넣는 것이 올바른 선택인지 고민됩니다.그 고민을 해결해보고자 이번에는 FSD에 대해 알아보고자 합니다.FSD 구조란기능 단위로 나누어 개발하는 방식으로, 프로젝트의 복잡도가 증가할 때 관리와 확장성을 쉽게 해주는 아키텍처 패턴입니다.FSD의 핵심 개념은 각 기능이 독립적인 모듈로 구성된다는 것!즉, UI 컴포넌트, 상태 관리, 스타일링, 비즈니스 로직 등을 하나의 기능 단위로 묶어서 관리합니다.다음과 같은 이점들이 있습니다.1.모듈화: 각 기능은 독립적인 모듈로 분리되어 있기 때문에, 다른 기능에 영향을 주지 않고 개발 및 수정이 가능합니다.2.유지보수 용이성: 기능별로 코드를 관리하므로 특정 기능에 문제가 발생했을 때 쉽게 문제를 파악하고 해결할 수 있습니다.3.협업 효율성: 팀원들이 각 기능별로 작업을 나누어 진행할 수 있기 때문에 대규모 프로젝트에서 협업이 더 원활합니다.4.재사용성: 기능별로 모듈화된 코드를 다른 프로젝트나 페이지에서도 쉽게 재사용할 수 있습니다.구조 예시/src /app # 앱 초기화 및 전역 설정 관련 (store, routing 등) /entities # 핵심 비즈니스 로직을 처리하는 객체들 (도메인 모델, 상태 등) /features # 개별 기능 단위 (서브 도메인) /pages # 페이지 구성 (라우팅된 주요 화면) /widgets # 페이지나 여러 기능에 걸쳐 재사용될 수 있는 UI 구성 요소들 /shared # 앱 전반에서 사용되는 공통 리소스 (유틸리티, 상수, API 함수 등)폴더 구조를 역할에 따라 나눈 후, 각 역할에 맞는 하위 폴더로 세분화합니다.예를 들어, 기능(feature)을 정리할 경우에는 다음과 같이 각 기능에 맞는 폴더를 구성합니다./features /write /delete /like
NEW
5
/ 5
Google Analytics를 세팅하여 내 페이지 통계를 확인해보자!
개요본 웹사이트를 만들고 나니, 그동안 티스토리만 사용해왔던 탓에 통계를 어떻게 확인할지 고민이 생겨,여러 자료를 찾아본 끝에 ‘Google Analytics’를 통해 통계를 확인해보기로 결정했습니다.어떻게 되는걸까요건 제가 예전에 등록했던 티스토리에 대한 통계인데요!만약 측정을 시작하면 이렇게 세세하게 내 페이지를 방문한 사용자들이나의 페이지를 어떻게 이용했는지, 어떻게 유입했는지 확인이 가능합니다.시작해보자1. Google Analytics 방문Google Analytics를 방문하면 왼쪽 하단의 톱니바퀴를 눌러주세요!2. + 만들기 클릭왼쪽 상단 '+ 만들기' - '속성' 클릭3. 속성 이름 및 보고 시간대 선택속성 이름은 이 사이트를 구분할 이름(원하는 이름), 보고 시간대는 한국을 선택하시면 됩니다.4. 내 사이트 카테고리전 교육이나 취업에 관련된 내용에 치중되어있다 생각되어서 '취업 및 교육'으로 선택하였습니다.규모는 '작음'으로 선택하였습니다.5. 비즈니스 목표 선택모든 항목에 대한 통계를 보기위해 모두 선택 후 '만들기를 선택하였습니다'6. head 태그 안에 Google Tag 관련 스크립트 추가만들기를 통해 나온 gtag 코드를 head태그에 삽입해주세요.예를 들어 아래 코드가 head 태그 안에 삽입 후 배포가 되어있어야Google Analytics가 접속해 확인이 가능합니다.<script> // <!-- Google tag (gtag.js) --> window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-');</script>완료!하단과 같이 '데이터 수집이 활성화되었습니다.' 가 표시되었다면 세팅이 완료된거에요이제 사람들이 우리들의 사이트를 어떻게 훑어보고 있는지 확인해보면 될거같습니다,,,,ʕ◍·̀·́◍ʔฅ
typescript
[3] 타입스크립트 선택적 타입을 통해 누락된 값이 있어도 타입 추론을 해보기
javascript
클로저란 무엇일까
typescript
[2] 타입스크립트의 타입 정의 상속에 대하여
php
PHP에서 좋아요 기능 구현하기
PHP를 이용해 웹사이트를 구현하는 도중 좋아요 기능이 필요할거 같아직접 구현해보기로 했습니다!1. 좋아요 테이블 만들기처음에는 마냥 게시물마다 누가 눌렀는지 멤버의 아이디를 게시물 마다 새겨넣는 방식으로 업데이트 해주는게 편할거 같다고 생각했는데이게 점점 쌓이면 쌓일수록 데이터도 커지고 유지보수에 여러모로 문제점이 많아 보였습니다...ㅠ그래서 좋아요 테이블에서 현재 게시물의 ID 값을 좋아요 테이블에서 찾아 좋아요수를 업데이트 하는 방법을 이용해보기로 했습니다.<?php // 최상위 경로 $rootPath = $_SERVER['DOCUMENT_ROOT']; // MySQL 연결 include $rootPath ."/src/components/common/component_connect.php"; $sql = " CREATE TABLE boardLikes( likeID int(10) unsigned NOT NULL auto_increment, postID int(10) NOT NULL, memberID int(10) NOT NULL, regTime TIMESTAMP DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (likeID) )DEFAULT CHARSET=utf8; "; $result = $connect ->query($sql); if ($result) { echo "좋아요의 테이블 생성을 성공 하였습니다."; } else { echo "테이블 생성에 실패 하였습니다.".$connect->error; }?>2. 좋아요 업데이트 관련 API 만들기좋아요를 구현하려고 했으나 새로고침 없이 하고자 했기 때문에 단순 눌렀을때 form을 통한 방식이 아닌 다른 방식이 필요했습니다,그래서 좋아요를 업데이트 해주는 api를 만들어 관련 api 호출을 통해 해결 하고자 하였습니다.<?php // 1. SQL 쿼리를 미리 준비 (prepare()). // 2. 쿼리의 변수 자리에 바인딩할 값을 지정 (bind_param()). // 3. 준비된 쿼리를 실행 (execute()). // 최상위 경로 $rootPath =$_SERVER['DOCUMENT_ROOT']; // MySQL 연결 include$rootPath ."/src/components/common/component_connect.php"; include$rootPath ."/src/components/common/component_session.php"; header('Content-Type: application/json'); $data = json_decode(file_get_contents("php://input"),true); $postID = $data['postID']; $memberID = $data['memberID']; // 먼저 로그인한 사용자가 이 게시물에 이미 좋아요를 눌렀는지 확인 $sql ="SELECT*FROM boardLikes WHERE memberID = ? AND postID = ?"; $result =$connect->prepare($sql); // i: 정수 (integer) // s: 문자열 (string) // d: 실수 (double) // b: 바이너리 데이터 (blob) $result ->bind_param("ii",$memberID,$postID); $result ->execute(); $result =$result ->get_result(); $isAvailiable =$result -> num_rows >0; // 이미 좋아요를 눌렀다면, 좋아요 취소 // 좋아요를 누르지 않았다면, 새로 좋아요 추가 $sql = $isAvailiable ?" DELETE FROM boardLikes WHERE memberID = ? AND postID = ? ":" INSERT INTO boardLikes (memberID, postID) VALUES (?, ?) "; $result = $connect->prepare($sql); $result -> bind_param("ii",$memberID,$postID); $result -> execute(); $message = $isAvailiable ? [ 'success'=>true,'message'=>'좋아요 취소됨','stat'=>0 ] : [ 'success'=>true,'message'=>'좋아요 추가됨','stat'=>1 ]; echo json_encode($message);?>3. 클릭 했을때 API를 호출하는 스크립트 구현클릭하였을때 API를 호출하는 부분을 구현해보고자 합니다.const postID = document.querySelector("#postID").value;const memberID = document.querySelector("#memberID").value;try{ const response = await fetch("/src/api/controller_like.php",{ method:"POST", headers:{ 'Content-Type':'application/json', }, body:JSON.stringify({ memberID: memberID, postID: postID, }), }); const result = await response.json(); return result.success && result.stat;} catch(error) { console.error("반영 중 실패:", error);}4. 클릭 했을때 좋아요 수 업데이트 및 연속 호출 방지이제 좋아요를 클릭했을때 위에서 작성했던 API 호출 및 연속 호출 방지를 해주었어요.저의 경우 요소를 선택할때 모든 .like 요소를 잡은 이유는다른 페이지에서 여러 게시물을 리스트업 하였을때 해당 게시물에 바로 바로 좋아요를 클릭해 개별적으로 업데이트 하기 위해 사용했어요.순서 : 좋아요 수 반영 -> 추가 이벤트 호출 막음 -> 1초 후 이벤트 호출 막음 처리 해제const elementsLike = document.querySelectorAll(".like");elementsLike.forEach((e,i)=>{ // 변수 : 이벤트 호출 방시 상태 let isNeedPrevent =false; // 함수 : 좋아요 상태 업데이트 const setLikeCount=(stat,element,value)=>{ stat ? e.classList.add("active"): e.classList.remove("active"); element.innerText = stat ? value +1: value -1; } // 함수 : 이벤트 호출 방지 상태 업데이트 const setStatePrevent=()=>{ isNeedPrevent = !isNeedPrevent; console.log("막기 상태", isNeedPrevent); } // 클릭 이벤트 : 좋아요 수 반영 -> 이벤트 호출 막음 설정 -> 이벤트 호출 막음 해제 e.addEventListener("click", async() => { const elementLikeCount = e.querySelector(".countLike"); if(!isNeedPrevent && elementLikeCount){ const value = parseInt(elementLikeCount.innerText); let result = await getLike(); setLikeCount(result, elementLikeCount, value); setStatePrevent(); setTimeout(() => setStatePrevent(),1000); } })});5. html 작성이제 마지막이네요!클릭해 함수를 작동시키고 표시해줄 버튼을 하단과 같이 만들어 두었습니다.<button type='button' class='item like'> <img src='/src/assets/images/icon/ico-like-stroke.svg' alt='좋아요'> <p class='countLike'>{$countLikes}</p></button>6. SCSS으로 스타일 입히기저의 경우엔 SCSS로 스타일 처리를 하는것이 편해 주로 이용하고 있어요.like 에 .active 가 붙었을때 이미지의 경로를 변경해주었습니다.또한 클릭했을때 심심하지 않게 눌렸을때(active) 크기를 조금 작게 변경해주었으며,마우스를 가져다 올려두었을때 배경(background) 의 색상을 변경해 조금 꾸며보았어요.> .item { &:active { transform:scale(0.95); } &:hover { background: blue; } &.like { &.active { > img { background-image:url('/src/assets/images/icon/ico-like-fill.svg'); } } }}마무리이런 과정을 거쳐 좋아요 기능을 만들어 보았습니다,만들고 나니 조금은 감정을 표현 할 수 있는 수단이 늘어 기분이 좋네요 ㅎㅎㅎ생각보다 복잡한 과정을 거치게 될줄 알았으나다행히 너무 큰 어려움 없이 구현하였네요제가 구현한 방식은 아무래도 많이 다듬어져 있지 않은 방식이라다른분들이 구현한 방식이 더 좋고 안정적인 방법일거라 생각합니다.참고용으로만 봐주세요!
2024-10-12