수코딩
@sucoding
수강생
4,877
수강평
272
강의 평점
4.9
수코딩은 온라인과 오프라인을 병행하면서
코딩을 가르치는 활동을 하고 있습니다.
다년간의 오프라인 강의 경험을 바탕으로,
더 많은 사람들이 코딩을 쉽고 재미있게 배울 수 있도록
매일 고민하고, 끊임없이 노력하고 있습니다.
현재까지 다음과 같은 4권의 책을 출판하며
프런트엔드 강의 분야를 선도하고 있습니다:
또한, 유튜브 채널을 통해 다양한 무료 강의도 제공하고 있습니다.
👇 지금 바로 방문해 보세요
[유튜브 채널 링크]
강의
로드맵
전체 2수강평
- 타입스크립트로 배우는 리액트(React.js) : 기초부터 최신 기술까지 완벽하게
- 타입스크립트로 배우는 리액트(React.js) : 기초부터 최신 기술까지 완벽하게
- 핵심만 골라배우는 HTML5
게시글
질문&답변
강의 수정이 좀 필요해보입니다.
안녕하세요, 5647kr님!with 키워드는 영상 촬영 당시에는 문제가 없던 키워드였으나,제보해주신 내용을 바탕으로 확인한 결과 현재는 deprecated된 스펙임을 확인했습니다.해당 영상에서는 with 부분을 삭제하고 in 부분만 남겨 수정 후 재업로드하였습니다.영상 시청에 불편을 드린 점 양해 부탁드리며,소중한 제보 감사드립니다.좋은 하루 보내세요!
- 1
- 2
- 21
질문&답변
함수 정의 기준
안녕하세요 정진 서님!리액트에서 함수를 어느 컴포넌트에 정의해야 하는지는 단순한 규칙보다는, 해당 함수가 어떤 역할을 수행하는지를 기준으로 판단하시는 것이 가장 적절합니다. 이를 이해하시기 쉽도록 설명 중간에 간단한 코드를 함께 섞어 설명드리겠습니다.우선, 상태를 변경하는 로직이나 애플리케이션의 핵심 동작과 관련된 함수는 보통 상위 컴포넌트에 정의하는 것이 일반적입니다. 예를 들어 상위 컴포넌트에서 count라는 상태를 관리하고 있다면, 이 값을 변경하는 함수 역시 상위 컴포넌트에 두는 것이 자연스럽습니다.function Parent() { const [count, setCount] = React.useState(0); const increaseCount = () => { setCount(count + 1); }; return ; } 이와 같이 상위 컴포넌트는 상태와 그 상태를 변경하는 함수를 함께 관리하고, 하위 컴포넌트에는 해당 함수를 props로 전달합니다. 이 구조는 리액트의 단방향 데이터 흐름 원칙에 잘 맞습니다.하위 컴포넌트에서는 이벤트가 발생했을 때 상위 컴포넌트에서 전달받은 함수를 호출하게 됩니다. 다만, 이 과정에서 하위 컴포넌트 전용 이벤트 처리 로직이 필요하다면, 하위 컴포넌트 내부에 함수를 정의하는 것도 매우 일반적인 패턴입니다.function Child({ onIncrease }) { const handleClick = () => { console.log("버튼이 클릭되었습니다."); onIncrease(); }; return 증가; } 위 코드에서 handleClick 함수는 하위 컴포넌트의 UI 이벤트를 처리하는 역할만 담당하고 있으며, 실제로 상태를 변경하는 책임은 상위 컴포넌트의 increaseCount 함수가 가지고 있습니다. 이러한 구조는 각 컴포넌트의 책임을 명확하게 분리해 줍니다.강의에서 하위 컴포넌트에도 함수가 정의되어 있는 것처럼 보이는 이유는 대부분 이와 같은 상황 때문입니다. 즉, 하위 컴포넌트에서 이벤트를 직접 처리하고, 필요한 경우 상위 컴포넌트의 함수를 호출하기 위해 중간 단계의 함수가 존재하는 것입니다.결론적으로, 상태를 변경하거나 여러 컴포넌트에 영향을 주는 로직은 상위 컴포넌트에 정의하는 것이 바람직하며, 이벤트 처리나 UI와 밀접한 로직은 하위 컴포넌트에 정의해도 전혀 문제가 없습니다. 결국 함수의 위치는 “이 로직이 어느 컴포넌트의 책임인가”를 기준으로 판단하시면 가장 혼란 없이 설계하실 수 있을 겁니다.
- 0
- 2
- 38
질문&답변
Exclude 이해
안녕하세요!Exclude는 객체의 속성을 비교하여 차이를 계산하는 타입이 아니라, 조건부 타입을 기반으로 T가 U에 할당 가능한지 여부를 판단하여 타입을 제거하거나 유지하는 역할을 합니다. 내부적으로 Exclude는 T extends U ? never : T 형태로 동작합니다.질문에 제시된 코드에서 T5는 name과 age 속성만을 가지고 있으며, U5는 여기에 더해 gender라는 필수 속성을 요구합니다. 따라서 T5는 U5에 할당될 수 없고, 이로 인해 T5 extends U5 조건은 성립하지 않습니다. 그 결과 Exclude의 결과 타입은 never가 아닌 T5가 됩니다.이 상황을 “두 객체의 속성이 모두 일치하지 않기 때문에 첫 번째 타입이 반환된다”라고 이해하는 것은 결과적으로는 맞을 수 있으나, 정확한 개념은 속성의 일치 여부를 비교하는 것이 아니라 할당 가능성(extends 관계)을 기준으로 판단한다는 점입니다.또한 Exclude는 주로 유니언 타입에서 특정 타입을 제거하기 위한 용도로 사용되며, 단일 객체 타입에 적용할 경우에는 실질적인 활용도가 크지 않습니다. 객체 타입에서 원하는 속성만 선택하거나 특정 속성을 제외하여 새로운 타입을 생성하고자 할 때에는 Pick이나 Omit을 사용하는 것이 적절합니다.따라서 질문에서 정리하신 것처럼, 객체 타입의 일부 속성만을 기준으로 새로운 타입을 만들고 싶을 경우에는 Pick이나 Omit을 사용한다고 이해하시면 올바른 방향입니다.
- 0
- 2
- 18
질문&답변
fetch는 사용되는가
안녕하세요.메인으로 사용하는 프레임워크가 리액트라면 fetch 보다는 axios를 더 많이 사용합니다.하지만 Next.js라면 axios 보다는 fetch를 더 많이 사용합니다.이는 두 프레임워크가 추구하는 방향이 다르기 때문인데요. 🙂이를 완벽히 이해하려면 결국 next.js까지 배워야 하기 때문에 지금 당장은 axios를 더 많이 사용하는구나라고 이해하고 계셔도 무방합니다!감사합니다.
- 0
- 2
- 40
질문&답변
전역상태 관리 선택 기준
안녕하세요.전역 상태 관리 방식에는 Redux Toolkit, Context API, Zustand가 있으며, 모두 전역으로 상태를 관리할 수 있다는 공통점을 가지고 있습니다. 다만 각 도구는 사용 목적과 적합한 프로젝트 규모, 그리고 상태의 복잡도에 따라 선택 기준이 달라집니다.먼저 Context API는 리액트에 기본으로 포함된 기능으로, 별도의 라이브러리 설치 없이 사용할 수 있다는 장점이 있습니다. 주로 다크 모드와 같은 테마 설정, 로그인 여부, 언어 설정처럼 구조가 단순하고 변경 빈도가 높지 않은 상태를 전역으로 공유할 때 적합합니다. 그러나 상태가 복잡해지거나 관리해야 할 데이터가 많아질 경우, 불필요한 리렌더링이 발생할 수 있고 유지보수가 어려워질 수 있다는 한계가 있습니다. 따라서 전역으로 공유해야 할 상태가 단순하고 규모가 작을 경우에 선택하는 것이 바람직합니다.Zustand는 비교적 가볍고 사용법이 간단한 전역 상태 관리 라이브러리로, 개인 프로젝트나 중소 규모의 프로젝트에서 자주 사용됩니다. 코드 작성량이 적고 직관적이며, 리렌더링 최적화가 기본적으로 제공되어 생산성이 높다는 장점이 있습니다. Context API로는 부족하지만 Redux Toolkit을 사용하기에는 부담스러운 경우에 좋은 대안이 될 수 있습니다. 다만 팀 규모가 크거나 엄격한 구조와 규칙이 필요한 프로젝트에서는 일관성을 유지하기가 다소 어려울 수 있습니다.Redux Toolkit은 대규모 프로젝트나 여러 명이 협업하는 환경에서 적합한 전역 상태 관리 도구입니다. 상태 구조와 흐름이 명확하게 정리되며, 비동기 처리, 미들웨어, 개발자 도구 등 다양한 기능을 제공하여 복잡한 상태 관리에 강점을 가집니다. 초기 설정과 학습 비용이 상대적으로 높다는 단점이 있지만, 장기적으로 유지보수가 중요한 서비스나 상태 로직이 복잡한 프로젝트에서는 가장 안정적인 선택이 될 수 있습니다.결론적으로 프로젝트에서 어떤 전역 상태 관리 도구를 선택할지는 상태의 복잡도, 프로젝트 규모, 협업 인원, 그리고 유지보수의 중요도를 기준으로 판단하는 것이 좋습니다. 단순한 전역 상태 공유에는 Context API가 적합하며, 빠른 개발과 높은 생산성이 필요한 경우에는 Zustand가 효과적입니다. 반면, 대규모 서비스나 복잡한 상태 흐름을 다뤄야 하는 프로젝트에서는 Redux Toolkit을 사용하는 것이 바람직합니다. 또한 모든 프로젝트에 반드시 전역 상태 관리가 필요한 것은 아니므로, 필요성을 충분히 검토한 후 도입하는 것이 중요합니다. (덧붙이자면 저는 대부분 zustand만 사용합니다. )
- 0
- 2
- 40
질문&답변
카카오 web플랫폼 등록
안녕하세요.이번 수업과 웹 훅은 관련이 없습니다. (웹 훅 기능 자체를 사용하지 않습니다)현재 리뉴얼된 카카오 개발자 센터 페이지에 대응하는 영상이"258. (25.12.07) 카카오 개발자 페이지 변경 내용 적용하기"에 올라간 상태입니다.해당 영상을 보시면 될 것 같습니다 (현재도 영상 내용과 다르지 않음을 확인했습니다.)감사합니다 🙂
- 0
- 2
- 52
질문&답변
tailwind css는 언제 사용되는가 또 다른 css와의 차이
안녕하세요.Tailwind CSS를 언제 사용해야 하는지에 대해 고민하시는 것은 매우 자연스러운 과정이라고 생각합니다. 리액트를 사용하다 보면 강의나 실무 예제에서 Tailwind CSS가 자주 등장하기 때문에, 마치 기본 선택지처럼 느껴질 수 있습니다. 실제로 최근 프론트엔드 개발 환경에서는 Tailwind CSS의 사용 빈도가 높은 편이지만, 그렇다고 해서 항상 정답이 되는 기술은 아닙니다.Tailwind CSS는 빠른 개발 속도가 중요한 상황에서 특히 적합한 선택입니다. 클래스 기반의 유틸리티 스타일을 JSX에 직접 작성함으로써 별도의 CSS 파일을 관리하지 않아도 되기 때문에, 디자인 수정이 잦거나 초기 단계의 프로젝트, MVP 개발과 같은 환경에서 생산성을 크게 높일 수 있습니다. 또한 디자인 규칙이 어느 정도 정형화되어 있고 반복되는 UI 패턴이 많은 경우에도 일관성을 유지하기 쉽다는 장점이 있습니다. 다만 JSX 코드가 길어질 수 있고, 스타일과 마크업이 강하게 결합된다는 단점도 함께 고려해야 합니다.CSS Module은 비교적 전통적인 CSS 작성 방식에 가깝기 때문에 협업과 유지보수가 중요한 프로젝트에 적합합니다. 컴포넌트 단위로 스타일 파일을 분리할 수 있고, 클래스 이름 충돌을 자동으로 방지해 주기 때문에 중·대규모 프로젝트에서도 안정적으로 사용할 수 있습니다. JSX 구조를 깔끔하게 유지하면서 스타일을 명확한 역할 단위로 관리하고 싶을 때 유용하며, 현재 실무에서도 여전히 많이 사용되고 있는 방식입니다.Styled Components는 스타일이 컴포넌트의 로직이나 상태에 따라 크게 달라지는 경우에 적합합니다. props를 기반으로 동적인 스타일을 적용할 수 있기 때문에 테마 전환이나 재사용 가능한 UI 컴포넌트를 설계할 때 강점을 가집니다. 다만 러닝 커브가 있고, 런타임 성능이나 번들 크기 측면에서 부담이 될 수 있어 최근에는 선택적으로 사용되는 추세입니다.실무에서는 특정 CSS 방식이 고정적으로 사용된다기보다는, 프로젝트의 성격과 팀 환경에 따라 선택이 이루어집니다. 빠른 개발과 생산성이 중요한 소규모 프로젝트에서는 Tailwind CSS가 적합한 경우가 많고, 장기적인 유지보수와 협업이 중요한 프로젝트에서는 CSS Module이 안정적인 선택이 될 수 있습니다. 또한 디자인 시스템이나 상태 기반 스타일링이 중요한 경우에는 Styled Components가 유용하게 활용될 수 있습니다.결국 중요한 것은 어떤 기술이 유행하고 있는지가 아니라, 해당 기술이 현재 상황과 목적에 적합한지 판단하는 기준을 갖는 것이라고 생각합니다. Tailwind CSS를 포함한 다양한 스타일링 방식을 경험해 보고, 각 방식의 장단점을 이해한 상태에서 상황에 맞는 선택을 할 수 있다면 실무에서도 충분히 경쟁력을 가질 수 있을 거라고 생각합니다.
- 0
- 2
- 75
질문&답변
컴포넌트 그리고 폴더 구조에 대해
안녕하세요!리액트에서 컴포넌트를 나누는 기준은 하나의 정답으로 정해져 있기보다는, 코드를 더 읽기 쉽고 이해하기 쉽게 만들기 위한 판단의 연속이라고 볼 수 있습니다. 처음 리액트를 공부하실 때 컴포넌트 분리가 어렵게 느껴지는 것은 매우 자연스러운 일이며, 대부분의 학습자들이 같은 고민을 겪습니다.컴포넌트를 나누는 가장 기본적인 기준 중 하나는 역할과 책임입니다. 하나의 컴포넌트는 가능한 한 하나의 역할에 집중하는 것이 좋으며, 서로 다른 역할을 하는 코드들이 한 컴포넌트 안에 섞여 있다면 분리를 고려해볼 수 있습니다. 또한 컴포넌트의 길이가 길어지고 JSX와 로직이 복잡하게 섞여 읽기 어려워진다면, 이 역시 분리가 필요하다는 신호로 볼 수 있습니다.컴포넌트 분리는 중복되는 UI가 있을 때만 하는 것은 아닙니다. 중복은 분리를 결정하는 강한 이유이긴 하지만, 가독성 향상이나 코드의 구조를 명확히 하기 위한 목적만으로도 충분히 컴포넌트를 나눌 수 있습니다. 특히 특정 부분의 코드가 “지금 이 컴포넌트의 핵심 역할과는 조금 다른 것 같다”는 느낌이 든다면, 그 부분을 별도의 컴포넌트로 분리하는 것이 전체 흐름을 이해하는 데 도움이 됩니다.처음부터 컴포넌트를 잘게 나누어 설계해야 한다는 부담을 가질 필요는 없습니다. 실제로는 하나의 컴포넌트로 구현을 시작한 뒤, 코드가 점점 길어지고 관리하기 어려워질 때 분리하는 방식이 더 자연스럽습니다. 컴포넌트 분리는 설계의 영역이기보다는 리팩토링의 과정에 가깝다고 생각하셔도 됩니다.폴더 구조 역시 정해진 정답은 없으며, 초보자일수록 본인이 찾기 쉽고 이해하기 쉬운 구조를 사용하는 것이 가장 좋습니다. 프로젝트의 규모가 커지기 전까지는 단순한 구조로 시작하고, 필요해질 때 점진적으로 정리해 나가도 충분합니다.마지막으로 컴포넌트 분리가 과한지 부족한지를 판단하는 가장 좋은 기준은 ‘읽기 쉬운가’입니다. 컴포넌트를 나누었을 때 오히려 흐름을 따라가기 어렵다면 과한 분리일 수 있고, 하나의 파일이 지나치게 길고 복잡하다면 분리가 부족한 상태일 수 있습니다. 결국 리액트에서 컴포넌트를 나누는 기준은 정해진 규칙이 아니라, 코드를 읽는 사람이 더 쉽게 이해할 수 있도록 만드는 방향이라고 정리할 수 있습니다.
- 0
- 2
- 38
질문&답변
152강 보는중입니다. 초시계부분이구요. 넘버가 timeout을 받을수없다는 에러가 나오고 있어요
안녕하세요!Vite로 설치하는 tsconfig.json 파일의 형식이 달라지면서이제는 아래처럼 NodeJS.Timeout 타입을 지정하셔야 합니다!useEffect(() => { let intervalId: NodeJS.Timeout; if (isRunning) { intervalId = setInterval(() => { setTime((time) => time + 10); }, 10); } return () => { if (intervalId) clearInterval(intervalId); }; }, [isRunning]);최근에 변경된 사항이라서 저도 이제 알았네요.감사합니다!
- 0
- 1
- 28
질문&답변
폼테그 다른 태그를 하나의 상태 객체로 묶기
안녕하세요 🙂리액트에서 폼을 구현할 때 input, textarea, radio, checkbox처럼 서로 다른 태그들을 하나의 객체 상태로 묶어서 관리하는 방식이 적절한지에 대한 고민은 실무에서도 자주 등장합니다. 이 방식이 옳은지, 혹은 각각의 상태를 분리해서 관리하는 것이 더 좋은지에 대해서는 하나의 정답이 존재한다고 보기는 어렵습니다. 다만 상황과 목적에 따라 더 적합한 선택지는 분명히 존재합니다.먼저 여러 폼 요소를 하나의 객체 상태로 관리하는 방식에 대해 살펴보겠습니다. 폼은 본질적으로 사용자가 입력한 값들의 집합이기 때문에, 이를 하나의 객체로 묶어 관리하는 것은 개념적으로 매우 자연스럽습니다. 예를 들어 다음과 같이 상태를 정의할 수 있습니다.const [form, setForm] = useState({ title: '', content: '', category: '', agree: false, }); 이 코드에서는 제목, 내용, 카테고리, 동의 여부와 같은 여러 입력값을 form이라는 하나의 객체로 관리합니다. 실무에서는 이 객체를 그대로 서버에 전달하는 경우가 많기 때문에, API 연동 시에도 효율적인 구조입니다.이 방식에서 중요한 부분은 공통 onChange 핸들러를 사용하는 것입니다.const handleChange = (e) => { const { name, value, type, checked } = e.target; setForm(prev => ({ ...prev, [name]: type === 'checkbox' ? checked : value, })); }; 이 코드는 모든 입력 요소의 변경 이벤트를 하나의 함수로 처리합니다. name 속성을 통해 어떤 필드가 변경되었는지를 구분하고, checkbox의 경우에는 checked 값을, 그 외의 입력 요소는 value 값을 상태에 반영합니다. 이를 통해 태그 종류에 관계없이 일관된 방식으로 폼 상태를 관리할 수 있습니다.객체로 폼 상태를 관리하는 방식의 장점은 폼 전체가 하나의 의미 단위로 묶인다는 점입니다. 구조를 이해하기 쉽고, 제출 시에도 별도의 가공 없이 바로 사용할 수 있습니다. 반면 일부 값만 변경되더라도 객체 전체를 복사해야 하므로, 폼이 매우 커질 경우에는 상태 업데이트 코드가 다소 복잡해질 수 있다는 단점도 존재합니다.다음으로 상태를 각각 분리해서 관리하는 방식입니다.const [title, setTitle] = useState(''); const [content, setContent] = useState(''); const [agree, setAgree] = useState(false); 이 방식은 각 입력값이 독립적인 상태를 가지도록 합니다. 어떤 값이 어떤 상태인지 명확하게 드러나기 때문에 직관적이며, 필드 수가 적거나 각 입력값이 서로 다른 로직을 가질 경우에는 관리하기가 수월합니다. 다만 필드가 늘어날수록 상태 선언과 이벤트 핸들러가 함께 증가하게 되고, 최종 제출 시에는 다시 하나의 객체로 묶어야 하는 번거로움이 발생할 수 있습니다.실무에서는 상태를 나누는 기준을 몇 가지 관점에서 판단합니다. 첫째, 해당 값들이 논리적으로 하나의 폼 데이터를 구성하는지 여부입니다. 하나의 제출 단위를 가진다면 객체로 묶는 것이 적절합니다. 둘째, 값들이 함께 변경되는지 여부입니다. 대부분 동시에 변경되고 함께 사용된다면 하나의 상태로 관리하는 편이 효율적입니다. 셋째, 폼의 복잡도입니다. 단순한 폼이라면 객체 하나로 충분하지만, 조건부 렌더링이나 복잡한 검증 로직이 많다면 다른 관리 방식이 필요할 수 있습니다.폼의 규모가 더 커지고 상태 변화 규칙이 복잡해질 경우에는 useReducer를 사용하는 패턴도 자주 활용됩니다.const reducer = (state, action) => { switch (action.type) { case 'CHANGE': return { ...state, [action.name]: action.value, }; default: return state; } }; 이 방식은 상태 변경 로직을 reducer 함수에 모아 관리할 수 있기 때문에, 복잡한 폼에서도 상태 흐름을 예측하기 쉽다는 장점이 있습니다.정리하자면, 서로 다른 폼 태그들을 하나의 객체 상태로 묶어서 관리하는 방식은 충분히 정석적인 접근이며, 실무에서도 가장 많이 사용되는 패턴 중 하나입니다. 다만 모든 상황에 동일하게 적용해야 하는 규칙은 아니며, 폼의 역할과 복잡도에 따라 상태를 분리하거나 관리 방식을 확장하는 것이 바람직합니다. 결국 중요한 것은 특정 패턴을 고집하는 것이 아니라, 현재 상황에서 가장 읽기 쉽고 유지보수하기 좋은 구조를 선택하는 것입니다.
- 0
- 2
- 28







