초급자를 위해 준비한
[웹 개발, 프론트엔드] 강의입니다.
리액트를 가장 쉽고 빠르게 배울 수 있는 리액트 입문 강의입니다. 토이 프로젝트를 만들면서 개념과 실전 감각을 익히고 배포까지 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)
댓글 남기기