초급자를 위해 준비한
[웹 개발, 프론트엔드] 강의입니다.
리액트를 가장 쉽고 빠르게 배울 수 있는 리액트 입문 강의입니다. 토이 프로젝트를 만들면서 개념과 실전 감각을 익히고 배포까지 3시간 만에 완성하는 알짜 강의! 초급, 중급, 고급으로 구성된 시리즈의 첫 번째 강의입니다 :)
✍️
이런 걸
배워요!
리액트 개발
프런트엔드 개발
웹 개발
나만의 토이프로젝트
백엔드 연동
강의 :
https://www.inflearn.com/course/만들면서-배우는-리액트-기초#
https://github.com/milooy/cat-jjal-maker/blob/main/answers/2-setup.html
[1. 인트로]
1 .강의 소개
강의 :
2 .프로젝트 개발환경 설정하기 - VSCode, GiHub
강의 :
format on save
3. 프로젝트 안내
강의 :
[2. 리액트가 왜 좋은가요?]
4. 웹사이트 움직이게 만들기
강의 :
5.리액트 맛보기
강의 :
중요!!!
리액트 18을 쓰시는 분들은 render라는 문법 대신 createRoot를 사용해주세요 :)
const 여기다가그려 = document.querySelector("#app");
// 리액트17 이하면?
ReactDOM.render(catItem, 여기다가그려);
// 리액트18 이면?
ReactDOM.createRoot(여기다가그려).render(catItem);
고양이 가라사대
1번째 고양이 가라사대
생성
6. Babel
강의 :
바벨은 다음과 같이 head 에 브라우저가 인식할 수있게 js 코드를 새롭게 그려 준다

7. JSX 로 HTML과 javascript 짬뽕하기
강의 :

index.html
고양이 가라사대
8. 퀴즈풀이
강의 :
[3. 리액트 앱 바닥부터 만들기]
9. 컴포넌트가 뭔가요?
강의 :

10. 컴포넌트 만들기
강의:
index.html
고양이 가라사대
11. 컴포넌트 퀴즈풀이
강의:
12. 컴포넌트 퀴즈풀이
강의:
스타일 주소
https://github.com/milooy/cat-jjal-maker/blob/main/answers/12-styling.html
~
const MainCard=({src,alt,width })=>{
return (<div className="main-card">
<img
src={src}
alt={alt}
width={width}
/>
<button>????</button>
</div>
);
}
~
function Favorites(){
return (
<ul className="favorites">
<CatItem img="http://placeimg.com/640/480/arch" title="cat1" />
<CatItem img="http://placeimg.com/640/480/nature" title="cat2" />
<CatItem img="http://placeimg.com/640/480/animals" title="cat3"/>
</ul>
)
}
13. 이벤트 다루기
강의:
~
const Form=()=>{
function handleFormSubmit(e){
e.preventDefault();
console.log("폼 전송 됨");
}
return (
<form onSubmit={handleFormSubmit}>
<input type="text" name="name" placeholder="영어 대사를 입력해주세요" />
<button type="submit">생성</button>
</form>
);
}
const MainCard=({src,alt,width })=>{
function handleHeartClick(){
console.log("하트 눌렀음");
}
function handleHeartMouseOver(){
console.log("하트 스쳐 지나감");
}
return (
<div className="main-card">
<img
src={src}
alt={alt}
width={width}
/>
<button onClick={handleHeartClick}
onMouseOver={handleHeartMouseOver}
>????</button>
</div>
);
}
~
14. useState로 상태 만들기
강의:
const Form=()=>{
const [counter ,setCounter ] =React.useState(1);
console.log("카우터" , counter);
function handleFormSubmit(e){
e.preventDefault();
setCounter(counter+1);
console.log("폼 전송 됨" ,counter);
}
return (
<form onSubmit={handleFormSubmit}>
<input type="text" name="name"
placeholder="영어 대사를 입력해주세요" />
<button type="submit">생성</button>
</form>
);
}
15. 상태끌어올리기
강의:
~
const Form=({handleFormSubmit})=>{
return (
<form onSubmit={handleFormSubmit}>
<input type="text" name="name"
placeholder="영어 대사를 입력해주세요" />
<button type="submit">생성</button>
</form>
);
}
~
const App=()=>{
const [counter ,setCounter ] =React.useState(1);
console.log("카우터" , counter);
function handleFormSubmit(e){
e.preventDefault();
setCounter(counter+1);
console.log("폼 전송 됨" ,counter , e.target.name.value);
}
return(
<div>
<Title>1번째 고양이 가라사대</Title>,
<Form handleFormSubmit={handleFormSubmit} />
<MainCard src="https://source.unsplash.com/random" alt="alt" width="400" />
<Favorites />
</div>
)
}
~
16. useState 퀴즈풀이
강의:
const mainImageSrcArr = [ "https://cataas.com/cat/HSENVDU4ZMqy7KQ0/says/react",
"https://cataas.com/cat/BxqL2EjFmtxDkAm2/says/inflearn",
"https://cataas.com/cat/18MD6byVC1yKGpXp/says/JavaScript",
"https://source.unsplash.com/random",
"http://placeimg.com/640/480/arch",
"http://placeimg.com/640/480/nature",
"http://placeimg.com/640/480/animals"
]
~
const MainCard=({mainCardImgSrc,alt,width })=>{
function handleHeartClick(){
console.log("하트 눌렀음");
}
function handleHeartMouseOver(){
console.log("하트 스쳐 지나감");
}
return (
<div className="main-card">
<img
src={mainCardImgSrc}
alt={alt}
width={width}
/>
<button onClick={handleHeartClick} onMouseOver={handleHeartMouseOver} >????</button>
</div>
);
}
~
const App=()=>{
const [counter ,setCounter ] =React.useState(1);
const [mainCardImgSrc, setMainCardImgSrc] =React.useState(mainImageSrcArr[0]);
function handleFormSubmit(e){
e.preventDefault();
setCounter(counter+1);
const nIndex= Math.floor(Math.random()* mainImageSrcArr.length);
setMainCardImgSrc(mainImageSrcArr[nIndex]);
console.log("폼 전송 됨" ,counter , e.target.name.value);
}
return(
<div>
<Title>1번째 고양이 가라사대</Title>,
<Form handleFormSubmit={handleFormSubmit} />
<MainCard mainCardImgSrc={mainCardImgSrc} alt="alt" width="400" />
<Favorites />
</div>
)
}
~
17. 리스트
강의:
~
function Favorites(){
const CAT1 = "https://cataas.com/cat/HSENVDU4ZMqy7KQ0/says/react";
const CAT2 = "https://cataas.com/cat/BxqL2EjFmtxDkAm2/says/inflearn";
const CAT3 = "https://cataas.com/cat/18MD6byVC1yKGpXp/says/JavaScript";
const cats=[CAT1,CAT2];
return (
<ul className="favorites">
{
cats.map(cat=>(
<CatItem img={cat} key={cat} />
))
}
</ul>
)
}
~
18.배웠던 개념 조합해서 기능 추가 (상태, prop, 이벤트, 리스트)
강의:
function Favorites({favorites}){
console.log(" favorites " ,favorites);
return (
<ul className="favorites">
{
favorites.map(cat=>(
<CatItem img={cat} key={cat} />
))
}
</ul>
)
}
const App=()=>{
const CAT1 = "https://cataas.com/cat/HSENVDU4ZMqy7KQ0/says/react";
const CAT2 = "https://cataas.com/cat/BxqL2EjFmtxDkAm2/says/inflearn";
const CAT3 = "https://cataas.com/cat/18MD6byVC1yKGpXp/says/JavaScript";
const cats= [CAT1,CAT2];
const [favorites , setFavorites]=React.useState(cats);
const [counter ,setCounter ] =React.useState(1);
const [mainCardImgSrc, setMainCardImgSrc] =React.useState(mainImageSrcArr[0]);
function handleFormSubmit(e){
e.preventDefault();
setCounter(counter+1);
const nIndex= Math.floor(Math.random()* mainImageSrcArr.length);
setMainCardImgSrc(mainImageSrcArr[nIndex]);
console.log("폼 전송 됨" ,counter , e.target.name.value);
}
function handleHeartClick(){
console.log("하트 눌렀음");
setFavorites([...favorites, CAT3])
}
return(
<div>
<Title>1번째 고양이 가라사대</Title>,
<Form handleFormSubmit={handleFormSubmit} />
<MainCard mainCardImgSrc={mainCardImgSrc} handleHeartClick={handleHeartClick} alt="alt" width="400" />
<Favorites favorites={favorites} />
</div>
)
}
19.폼 다루기
강의:
const Form=({handleFormSubmit})=>{
const [value, setValue] =React.useState("");
function handleInputChange(e){
setValue(e.target.value.toUpperCase()) ;
}
return (
<form onSubmit={handleFormSubmit}>
<input type="text" name="name" placeholder="영어 대사를 입력해주세요"
value={value}
onChange={handleInputChange}
/>
<button type="submit">생성</button>
</form>
);
}
20.폼 검증하기
강의:
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>고양이 가라사대</title>
</head>
<style>
body {
text-align: center;
}
.main-card button {
position: relative;
left: -45px;
bottom: 15px;
}
.favorites {
list-style: none;
display: flex;
justify-content: center;
flex-wrap: wrap;
gap: 15px;
}
.favorites img {
width: 150px;
}
form{
margin-bottom: 20px;
}
</style>
<body>
<div id="app"></div>
<!-- React를 실행. -->
<!-- 주의: 사이트를 배포할 때는 "development.js"를 "production.min.js"로 대체하세요. -->
<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<script type="text/babel">
const mainImageSrcArr = [ "https://cataas.com/cat/HSENVDU4ZMqy7KQ0/says/react",
"https://cataas.com/cat/BxqL2EjFmtxDkAm2/says/inflearn",
"https://cataas.com/cat/18MD6byVC1yKGpXp/says/JavaScript",
"https://source.unsplash.com/random",
"http://placeimg.com/640/480/arch",
"http://placeimg.com/640/480/nature",
"http://placeimg.com/640/480/animals"
]
const Title= (props)=>(
<h1>{props.children}</h1>
)
const Form=({counter , setCounter, setMainCardImgSrc })=>{
const includesHangul = (text) => /[ㄱ-ㅎ|ㅏ-ㅣ|가-힣]/i.test(text);
const [value, setValue] =React.useState("");
const [errorMessage , setErrorMessage] =React.useState("");
function handleInputChange(e){
const useValue=e.target.value;
setErrorMessage("");
if(includesHangul(useValue)){
setErrorMessage("한글은 입력할 수 없습니다.");
}
setValue(e.target.value.toUpperCase()) ;
}
function handleFormSubmit(e){
e.preventDefault();
setErrorMessage("");
if(value===''){
setErrorMessage("빈값으로 만들 수 없습니다.");
}
setCounter(counter+1);
const nIndex= Math.floor(Math.random()* mainImageSrcArr.length);
setMainCardImgSrc(mainImageSrcArr[nIndex]);
console.log("폼 전송 됨" ,counter , e.target.name.value);
}
return (
<form onSubmit={handleFormSubmit}>
<input type="text" name="name" placeholder="영어 대사를 입력해주세요"
value={value}
onChange={handleInputChange}
/>
<button type="submit">생성</button>
<p style={{color:"red"}}>{errorMessage}</p>
</form>
);
}
const MainCard=({mainCardImgSrc, handleHeartClick ,alt,width })=>{
return (
<div className="main-card">
<img
src={mainCardImgSrc}
alt={alt}
width={width}
/>
<button onClick={handleHeartClick} >????</button>
</div>
);
}
function CatItem(props){
return (
<li>
<img src={props.img} style={{width:"150px"}} />
</li>
);
}
function Favorites({favorites}){
console.log(" favorites " ,favorites);
return (
<ul className="favorites">
{
favorites.map(cat=>(
<CatItem img={cat} key={cat} />
))
}
</ul>
)
}
const App=()=>{
const CAT1 = "https://cataas.com/cat/HSENVDU4ZMqy7KQ0/says/react";
const CAT2 = "https://cataas.com/cat/BxqL2EjFmtxDkAm2/says/inflearn";
const CAT3 = "https://cataas.com/cat/18MD6byVC1yKGpXp/says/JavaScript";
const cats= [CAT1,CAT2];
const [favorites , setFavorites]=React.useState(cats);
const [counter ,setCounter ] =React.useState(1);
const [mainCardImgSrc, setMainCardImgSrc] =React.useState(mainImageSrcArr[0]);
function handleFormSubmit(e){
e.preventDefault();
setCounter(counter+1);
const nIndex= Math.floor(Math.random()* mainImageSrcArr.length);
setMainCardImgSrc(mainImageSrcArr[nIndex]);
console.log("폼 전송 됨" ,counter , e.target.name.value);
}
function handleHeartClick(){
console.log("하트 눌렀음");
setFavorites([...favorites, CAT3])
}
return(
<div>
<Title>1번째 고양이 가라사대</Title>,
<Form handleFormSubmit={handleFormSubmit} counter={counter} setCounter={setCounter} setMainCardImgSrc={setMainCardImgSrc} />
<MainCard mainCardImgSrc={mainCardImgSrc} handleHeartClick={handleHeartClick} alt="alt" width="400" />
<Favorites favorites={favorites} />
</div>
)
}
const 여기다가그려=document.querySelector("#app");
ReactDOM.createRoot(여기다가그려).render(<App />);
</script>
</body>
</html>
21.코드 정리하기
강의:
~
const MainCard=({mainCardImgSrc, onHeartClick ,alt,width })=>{
return (
<div className="main-card">
<img
src={mainCardImgSrc}
alt={alt}
width={width}
/>
<button onClick={onHeartClick} >????</button>
</div>
);
}
const App=()=>{
const CAT1 = "https://cataas.com/cat/HSENVDU4ZMqy7KQ0/says/react";
const CAT2 = "https://cataas.com/cat/BxqL2EjFmtxDkAm2/says/inflearn";
const CAT3 = "https://cataas.com/cat/18MD6byVC1yKGpXp/says/JavaScript";
const cats= [CAT1,CAT2];
const [favorites , setFavorites]=React.useState(cats);
const [counter ,setCounter ] =React.useState(1);
const [mainCardImgSrc, setMainCardImgSrc] =React.useState(mainImageSrcArr[0]);
function handleFormSubmit(e){
e.preventDefault();
setCounter(counter+1);
const nIndex= Math.floor(Math.random()* mainImageSrcArr.length);
setMainCardImgSrc(mainImageSrcArr[nIndex]);
}
function onHeartClick(){
setFavorites([...favorites, CAT3])
}
function updateMainCat(){
setCounter(counter+1);
const nIndex= Math.floor(Math.random()* mainImageSrcArr.length);
setMainCardImgSrc(mainImageSrcArr[nIndex]);
}
return(
<div>
<Title>1번째 고양이 가라사대</Title>,
<Form updateMainCat={updateMainCat} />
<MainCard mainCardImgSrc={mainCardImgSrc} onHeartClick={onHeartClick} alt="alt" width="400" />
<Favorites favorites={favorites} />
</div>
)
}
22.로컬스토리지에 데이터 싱크하기
강의:
~
const [counter ,setCounter ] =React.useState(Number(localStorage.getItem("counter")));
~
function updateMainCat(){
const nextCounter =counter+1;
setCounter(nextCounter);
localStorage.setItem("counter",nextCounter);
const nIndex= Math.floor(Math.random()* mainImageSrcArr.length);
setMainCardImgSrc(mainImageSrcArr[nIndex]);
}
~
23.로컬스토리지에 데이터 싱크하기 2
강의:
~
const jsonLocalStorage = {
setItem: (key, value) => {
localStorage.setItem(key, JSON.stringify(value));
},
getItem: (key) => {
return JSON.parse(localStorage.getItem(key));
},
};
~
function updateMainCat(){
const nextCounter =counter+1;
setCounter(nextCounter);
jsonLocalStorage.setItem("counter",nextCounter);
const nIndex= Math.floor(Math.random()* mainImageSrcArr.length);
setMainCardImgSrc(mainImageSrcArr[nIndex]);
}
[4. 지금까지 만든 앱 배포하기]
24.github pages 로 1차 배포
강의:
???? Push가 안될 때 해결 방법
깃헙 아이디, 비밀번호 입력시
'Support for password authentication was removed on Au.. Please use a personal access token instead'
란 에러가 뜰 수 있습니다.
2021년 8월 13일부터 평문 비밀번호를 못 쓰도록 보안 업데이트가 되었기 때문인데요,
비밀번호 대신 Personal access token을 입력하면 됩니다.
아래 링크 참고하셔서 깃헙 사이트에서 토큰을 만드시고, 얘를 비밀번호처럼 이용하시면 됩니다.
메모장같은곳에 적어둬서 잊지 않도록 해주세요~
공식 문서: https://docs.github.com/en/github/authenticating-to-github/keeping-your-account-and-data-secure/creating-a-personal-access-token
한글 블로그 글: https://jootc.com/p/201905122828
- git 다운로드 페이지
- Github
- Git 명령어
- 이름 설정 : git config –global user.name 이름
- 이메일 설정: git config –global user.email 이메일
- 팀 개발을 위한 Git, GitHub 입문(강의)
- 팀 개발을 위한 Git, GitHub 시작하기(책)
[5. 중간 정리]
25 지금까지 배운 개념 정리 1(JSX, 바벨, 컴포넌트,스타일링, 이벤트)
강의:
26. 지금까지 배운 개면 정리 2(상태,리스트,폼,로컬스토리지)
강의:














댓글 ( 4)
댓글 남기기