react를 시작하기 위해 먼저 준비해야 할 것들이 있다.
nodeJS
> node -v
v16.13.2
: -v 명령어로 설치 여부와 버전 확인 가능.
설치돼있지 않다면 https://nodejs.org/en/ 이 링크에서 설치.

npm (Node Packaged Manager)
> npm -v
8.1.2
: -v 명령어로 설치 여부와 버전 확인 가능.
nodejs 설치시 같이 설치된다.
npx
> npx -v
8.1.2
: -v 명령어로 설치 여부와 버전 확인 가능.
설치되어 있지 않을 경우 npm을 통해 설치 가능.
> npm install npx -g
create-react-app
> npx create-react-app {app 이름}
이렇게 만들어진 app(폴더)을 VScode를 통해 열어서 > npm start 명령어를 입력하면 아래처럼 프로젝트가 시작된다.

VScode를 통해 프로젝트를 열면 아래와 같은 파일들이 확인된다.

: node_modules는 package.json 파일만 수정되지 않았으면 npm으로 다시 설치할 수 있다. 때문에 깃에 올릴 때도 이 폴더는 잘 올리지 않는다. 크기도 크고 파일도 너무 많기 때문.
Hot Module Replacement (HMR)

: 코드를 작성하거나 수정한 후 저장하면 브라우저에 바로 반영이 된다. (HMR)
✨TIP!!
프로젝트 내리기 (ctrl+c)
올리기 (npm start)
JSX(JavaScrip XML) 작성하기


리액트 컴포넌트
: 리액트로 만들어진 앱을 이루는 최소한의 단위
: 기존의 웹 프레임워크는 MVC방식으로 분리하여 관리하여 각 요소의 의존성이 높아 재활용이 어렵다는 단점이 있음
: 반면 컴포넌트는 MVC의 뷰를 독립적으로 구성하여 재사용을 할 수 있고 이를 통해 새로운 컴포넌트를 쉽게 만들 수 있다.
: 컴포넌트는 데이터(props)를 입력받아 View(state) 상태에 따라 DOM Node를 출력하는 함수.
: 컴포넌트 이름은 항상 대문자로 시작하도록 한다.
(리액트는 소문자로 시작하는 컴포넌트를 DOM 태그로 취급하기 때문이다.
: UI를 재사용 가능한 개별적인 여러 조각으로 나누고, 각 조각을 개별적으로 나누어 코딩한다.



: 이런 식으로 만든 컴포넌트들은 어디에든 몇번이든 여러번 중복 사용이 가능하다.
컴포넌트의 위치 확인하기


- index.css 는 전체 프로젝트에 영향을 미치는 css
- App.css는 app component에 한정돼있는 css
여기서 주의할점 : App.css는 App.js에만 적용되는 것이 아님
![]()
: css style이 head 안에 작성이 되기 때문에 각각의 컴포넌트에 style을 주기 위해서는 css module을 활용해야 한다
- css module 적용 방법
: ##.module.css 파일을 만들어 css style을 입력한다
: import 방식은 import styles from "./##.module.css"
class 지정 방식은 className={styles.해당 클래스명}
![]()
: 위의 방식을 활용해서 App.module.css와 Hello.module.css를 나눠준 결과 동일한 클래스명을 가진 box가 각각의 컴포넌트에 다르게 적용되는 것을 확인할 수 있다
++팀프로젝트를 진행하면서 각각 작성한 CSS가 클래스명이 겹치는 것 때문에 좀 불편하다는 생각을 했었는데 react로 이런 부분을 단번에 해결할 수 있다는 것이 신기하고 재미있다...
- 이벤트 처리하는 2가지 방법
: ① 함수를 만들어서 함수명으로 반환
② 내부에 직접 함수 작성 장점: 매개변수를 전달하기 쉽다
![]()
: showText 함수로 event target의 value가 변할 때마다 console 창에 보여준다.
: 이런 식의 변형도 가능하다
- 기존 바닐라 자바스크립트의 방식
- react useState
: 좀더 간결하게 사용이 가능해지고 동일한 컴포넌트라도 다른 state에 영향을 끼치지 않으며 각각 관리가 된다.
: App.js에 각각의 컴포넌트에 age 지정.
: 화면상으로 변경되고 있는 것은 넘겨받은 age 값이 아닌const [age, setAge] = useState(props.age);의 값을 바꿔주는 것.
: 동일한 컴포넌트이기 때문에 change를 클릭했을 때 위아래 동시에 이름이 변경된다.
: db를 대신할 dummy 데이터를 만들고 DayList.js로 불러온다
: Header.js 작성
: App.js에 Header와 DayList를 불러온다
: console 창에서 더미 테이블 확인
: data.json에 있는 day 정보를 li 목록에 Day list로 부른다
: dummy 단어들에 필터를 걸어서 단어의 날짜가 n인 것만 출력
++ TIP!!

: 변수를 선언하더라도 ESLint가 인지하지 못해 종종 에러를 일으킬 수 있다. 이럴 경우
//eslint-disable-line no-unused-vars
를 해당 코드 옆에 주석으로 입력해주면 오류가 해결된다.

- 강의는 v5 버전으로 진행됨. 업데이트된 버전의 강의를 들으려면 아래 링크 참조.
- v6 삭제 : npm uninstall react-router-dom
v5 설치 : npm install react-router-dom@5.2.0- https://velog.io/@velopert/react-router-v6-tutorial
- https://www.youtube.com/watch?v=CHHXeHVK-8U
설치 후 App.js에 import 후
import { BrowserRouter, Route, Switch } from 'react-router-dom';
앱 전체를 BrowserRouter로 감싸주고 헤더와 푸터를 제외한 곳에 Switch(v6: Routes) 입력.
(Switch 내부의 공간은 url에 따라 다른 페이지, 외부 공간은 모든 페이지에 공통으로 들어가는 부분(Header/Footer))
- App.js
:<Route path="/day/:day">의 :(콜론)은 변화하는 url을 처리할 때 이용함.
- DayList.js
: react router는a가 아닌<Link>를 사용함
- Day.js
- EmptyPage.js
그런데 Day.js에서 문제가 있는 건지 뭔가 제대로 다운이 안 된건지 페이지 경로상으로만 표시가 되고 이동이 전혀 일어나지 않는다.. json이 확인이 안됨.. 누락한 부분이 있는지 강의를 몇번이고 돌려봤는데 못 찾았다 시간이 아까워서 일단 넘어가는데 분명 자잘한 실수일텐데.. 모를땐 너무 답답하다
이렇게 따로 검색하면 또 이동은 되네.. 이상하다.. 보니까 댓글에 비슷한 오류를 겪는 사람들이 꽤 있는 것 같은데 ㅠㅠ 버전 문제일까? 일단은 수업 들으면서 이해해보고.. v6을 다시 설치해서 다른 것도 알아봐야겠다..
- Day.js
: 체크박스와 뜻보기/삭제 버튼 만들어주기
- Word.js
++ Day.js에 있던 table을 Word라는 별도의 컴포넌트를 만들어서 그쪽으로 옮겨주고 Day에는 Word를 불러오기만 해준다.
<button onClick={toggleShow}>뜻 {isShow ? "숨기기" : "보기"}</button>



- json server 설치
npm install -g json-server
빠르고 쉽게 REST API를 구축해줘서 공부 목적이나 미니 프로젝트 만들시에 유용하다
설치 완료 후
json-server --watch ./src/db/data.json --port 3001
REST API => url 주소와 메서드로 CRUD 요청하는 것
Create : POST
Read : GET
Update : PUT
Delete : DELETE
dummy data import 삭제
useEffect
상태값이 변경돼서 다시 렌더링된 다음 호출되는 함수 작성 가능
- click할때마다 state가 변경되는 이벤트
:const [days, setDays] = useState([]);
빈 배열로 만들고 API에서 list를 가져와서 바꿔줄 것
위와 같은 버튼을 만든 상태에서 Day Change 버튼을 만든 후 실행해보면 아래와 같은 문제가 생긴다.


:숫자 버튼을 클릭하지 않았음에도 console창에 count change가 출력되는 것. (불필요한 실행이 일어나고 있음)


++ useEffect를 사용하는 목적은 API를 호출하는 것(렌더링이 되고 API를 호출한다)이기 때문에 렌더링이 완료되고 최초의 한번만 API를 호출해줄때는 의존성 배열을 지우고, 빈 배열을 입력하면 된다.

- API 호출 - fetch

import { useEffect, useState } from "react";
export default function useFetch(url) {
const [data, setData] = useState([]);
useEffect(() => {
fetch(url)
.then(res => {
return res.json()
})
.then(data => {
setData(data);
});
}, [url]);
return data;
}
data라는 상태값이 있고 API주소(url) 넘겨받아서 설치하고 응답하는 데이터를 셋팅해준 후 리턴해준다.
CRUD
Create: POST
Read: GET
Update: PUT
Delete: DELETE
- put (수정)
fetch 두번째 인자 객체에는 요청의 옵션을 입력한다. 수정하기 위한 정보를 body안에 입력하고 기존 데이터 …word에 isDone을 바꿔서 넣어준다. 그리고 리턴된 Promise 객체 응답이 ok면 상태를 바꿔준다.
- delete (삭제)
삭제 요청 후 ok 응답을 받으면 컴포넌트 다시 렌더링 해줘야 삭제된 게 확인된다. word 상태선언, 이때 props로 받는 word는 w라는 새로운 변수로 할당해준다. {word: w} : props로 넘어온 word를 w라는 변수명으로 사용하겠다는 의미. 삭제되면 word의 id를 0으로 변경하고, word의 id가 0이면 null을 return한다.
- CreateWord 컴포넌트 생성
:e.preventDefault();저장 버튼(onSubmit) 눌렀을 때 새로고침되는 걸 막아준다.
![]()
: App.js와 Header.js에도 연결.
- useRef
![]()
: 돔에 접근할 수 있게 해준다.
:스크롤 위치를 확인하거나 포커스를 줄 때 사용.
:useRef 생성해서 할당해준후 돔 요소 생성후 접근, 저장 버튼을 클릭하고 렌더링 결과가 dom에 반영된 직후 current로 해당 요소에 접근해서 value(input에 입력된 값)을 얻는다.
- 결과 확인
- CreateDay