React로 웹 개발 하기
2021.10.07
1. React 설치
1.1. 사전 설치
-
Node.js 터미널에서
node -v
로 버전 확인 버전이 나오면 설치가 되어 있는 것 설치가 되어 있지 않다면 https://nodejs.org/에서 LTS버전을 다운 또는brew install node
-
Npm (Node Package Manager)
npm -v
으로 버전 확인버전이 나오면 설치 되어 있는 것
설치가 되어 있지 않으면
-
Yarn npm과 같은 패키지 매니저 npm보다 안정성이나 보안성이 좋아서 사용한다고 함
yarn -v
으로 버전 확인 후 나오지 않으면brew install yarn --ignore-dependencies
설치 (이 때 npm을 설치하였으면 뒤에 —ignore-dependencies을 해주어야함) -
VSCode 편집기
node, yarn brew로 업데이트
brew upgrade node
brew upgrade yarn
1.2. React 설치
1.2.1 리액트 프로젝트 생성 도구 설치
create-react-app 설치 방법
yarn으로 설치함
- npm 설치 시
npm install -g create-react-app
- yarn 설치 시
yarn global add create-react-app
설치확인
1.2.2 프로젝트 만들기
create-react-app 이름
으로 생성 가능
폴더 주의 할 것 !
만들려는 폴더 경로에서 명령어 실행
위 사진과 같이 설치가 완료된 것을 확인 할 수 있다.
마지막 줄에 잇는 것을 그대로 명령어에 각각 쳐주면
cd 프로젝트명 yarn start
프로젝트가 생성된 것을 알 수 있다.
1.2.3. React Router
-
설치
yarn add react-router-dom npm install react-router-dom
-
초기 세팅 index.js
⇒<App />
컴포넌트를 Id가 root인 것에다가<App />
을 붙여라 라는 뜻 ⇒ 여기에 라우터 세팅 다음 코드를import
와ReactDom.render
사이에 넣는다.import { Brows erRouter } from 'react-router-dom';
⇒ (import에 ' ./ ' 가 없고 그냥 이름만 써있으면 라이브러리 이름임) 그리고
<App/>
을<BrowserRouter>
로 감싸주면 된다. -
라우터 세팅 끝 붉은색 박스
import
추가하고 파랑색박스로<APP/>
감싸기
1.2.4. BrowserRouter vs HashRouter
BrowserRouter 자리에 HashRouter를 그대로 넣을 수 있디.
- 차이점
- HashRouter를 복붙하시면 사이트 방문시 URL 맨 뒤에 /#/이 붙은채로 시작합니다.
- BrowserRouter를 복붙하시면 사이트 방문시 # 그런거 없이 깔끔해집니다.
⭐ HashRouter를 쓰는 이유 원래는 브라우저 주소창에 뭔가 페이지를 입력하면 서버에게 특정 페이지좀 보여달라는 요청이 된다. 그런데 우리는 요청할 서버가 없고 그냥 리액트가 라우팅을 담당한다. → 그래서 잘못하면 있지도 않은 페이지를 요청해서 404 Page Not Found 이런 에러도 뜨고 그럴 수 있기 때문에 실수로 서버에게 요청하지 않게 하려고 안전하게 # 사용 → 왜냐면 브라우저 주소창에 # 뒤에 붙은 것들은 절대 서버로 요청 되지 않으니까
⭐ 그러면 BrowserRouter가 안좋은 것일 까? 그런건 아니고 서버에서 셋팅을 잘해 주면 된다. ~이런 경로로 들어오는 요청은 404로 보내지 말고 리액트가 라우팅하게 해주세요 ~이런 경로로 들어오는 요청은 메인 페이지로 보내주세요 와 같이 되기 때문에 API를 잘 짜면 된다.
2. React 구조
2.1. 화면 출력 구조
2.1.1 src/index.js
package.json
을 보면
react
와 react-dom
이 들어 있다
이걸 src/index.js
파일 에서 보면
/App
을 임포트해서 중간에 reactDOM.reder을 보면 거기에 먼저 불러주고 그 아래에 document.getElementById('root')
가 있는데 public/index.html
파일의 id=root
인 파일에 보여준다는 내용이다.
그리고 <React.StrictMode>
로 App이 감싸져 있는데 Strict모드는 개발 모드에서만 활성화되기 때문에, 프로덕션 빌드에는 영향을 끼치지 않는다고 한다.
(지워도 무관)
2.1.2 파일로 보기
(위에 설명과 같은 내용임)
2.2. CSS 작성하기
App.js
파일을 보면import './App.css'
가 있다. ⇒ 이 파일에 css를 작성src/App.js
src/App.css
2.3. HTML
import React, { useState } from "react";
import logo from "./logo.svg";
import "./App.css";
function App() {
// javascript 영역
return (
// HTML 영역
);
}
export default App;
-
이미지의 경우 2번쨰 줄의 logo.svg처럼 import시키고
{ 변수 }
처럼 사용 가능 ( 데이터 바인딩 참조 ) -
HTML, JS는 각각 위의 영역에 작성하면 된다.
⇒ 단, return에 는 하나의 태그로 시작해서 하나의 태그로 한다.
- 가능
return <div></div>;
return ( <div> <div></div> </div> );
- 불가능
div가 두개가 시작되고 끝난다.
이렇게 할꺼면 하나의
<div>
로 감싸고 해야한다.return( <div></div> <div></div> );
- 가능
3. JSX 데이터 바인딩
3.1. 태그 - 클래스
- 리액트는 클래스를 부여할 때 className을 사용한다.
<div class="black-nav"></div> // 기존JS
<div className="nav"></div> // react
3.2. 데이터 바인딩
데이터 바인딩 변수나 함수의 값을 넣기 쉽다
일반 JS에서는 document.getElem~.innerHTML = ~~ 이런식으로 매우 길게 했지만 react는 쉽게 가능 한다
3.2.1. 일반적인 JS데이터값 바인딩
⇒ 변수명 뿐만 아니라 함수도 가능
3.2.2. 이미지 데이터 바인딩
그냥 src=" "해서 이미지를 넣을 수 있긴 하다.
3.2.3. 클래스명 바인딩
클래스 안에 값을 데이터 바인딩해서 CSS효과를 넣다 뺏다 하기 쉬움
3.2.4. Style 속성 바인딩
<div style={ }> 스타일 </div>
<div style={ {color : 'blue', fontSize:'30px'} }> 스타일 </div>
- 변수로 스타일을 지정해서 값을 넣을 수 있다.
3.3. UseState
- 리액트 데이터 저장공간
- 변수 대신 사용할 수 있는 데이터 저장공간
- 문자, 숫자, array, object 다 저장가능
-
상단에 useState를 import
-
useState는 [state데이터, state데이터 변경 함수 형식]
let [이름, 이름변경] = useState("값"); // { }사이에 이름을 넣으면 됨
-
UseState() ES6 destructuring
- 원래 방식
var array = ["Kim", 20]; var name = array[0]; var age = array[1];
- 신문법 방식
var [name, age] = ["Kim", 20];
- 원래 방식
-
글제목 부분만 출력
⇒ 남자 코트 추천
let [글제목, 글제목변경] = useState("남자 코트 추천"); <h3>{글제목}</h3>;
-
두개다 나오게 ⇒ 남자 코트 추천강남 우동 맛집
let [글제목, 글제목변경] = useState("남자 코트 추천", "강남 우동 맛집"); <h3>{글제목}</h3>;
-
배열로 선택 ⇒ 강남 우동 맛집
let [글제목, 글제목변경] = useState("남자 코트 추천", "강남 우동 맛집"); <h3>{글제목[1]}</h3>;
3.3.1. State에 데이터를 저장하는 이유
- 웹이 App처럼 동작하게 할 수 있음
- 변경이 될 때 제목이 바뀌거나 순서가 수정 될때 State는 변경 되면 HTML이 새로고침이 없어도 자동으로 재렌더링됨 (일반 변수에 넣어 놓을 경우 새로 고침을 할 경우만 변경됨)
거의 바뀌지 않은 거는 하드 코딩해놔도 괜찮다.
하지만 자주 바뀌는 경우 State를 사용하면 된다.
3.4. props
Modal이라는 컴포넌트가 있고, datas라는 배열이있다 datas라는 배열의 값들을
Modal()
에 넣어 각각 title1, title2, title3를 출력할 경우의 코드가 있다.
function App(){
let [datas, datasEdit] = useState(['title1','title2','title3'])
return (
<Modal></Modal>
<Modal></Modal>
<Modal></Modal>
)
}
function Modal(){
<h2>제목 : { datas } </h2>
}
⇒ 위 코드는 Modal( datas )라는 파라미터로 값을 전달하지 못한다.
이유는, datas는 App()안에 잇는 데이터고 Modal은 그 밖에 있다.
그래서 App가진 state를 쓸 수 있게 정송해야 한다.
⇒ 이게 props라는 문법이다.!!
- props 문법을 사용 하기
다음과 같이 쓸 수 있다.
<컴포넌트명 작명 = {state명} ></컴포넌트명>
=<Modal propsModal = {datas}></Modal>
⇒ 각 번호 설명function App() { let [datas, datasEdit] = useState(["title1", "title2", "title3"]); return ( <Modal propsModal={datas}></Modal> // 1 ); } function Modal(props) { // 2 <h2>제목 : {props.datas[0]} </h2>; // 3 }
-
컴포넌트에 propsModal이름으로 datas를 보낸다.
-
아래 Modal 파라미터를 만듬 (자유이나 props는 관습적으로 씀)
-
props를 쓰자마자 props에 전부 담겨 있음
→ (가져온 props의 datas의 0 번쨰 === props.datas[0])
-
3.5. 외부 데이터 바인딩 (import/export)
내보내기 : export default 변수명
가져오기 : import 변수명 from 경로
- 예제 코드
다음
var name = "kim"; export default name;
name
을 export로 내보내기를 하여서 다른 곳에서 사용할 수 있다 아래 코드와 같이import 변수명 from 경로 사용
을 상단에 적고return( ) 안에 (=HTML 코드 영역)에 데이터 바인딩 하는 것처럼 적어 주면된다.import namedata from "./data.js";
import namedata from './data.js' function(){ return( <div> { name } </div> ) }
- ⭐ 참고 사항
export 할때는 파일 하나당 하나씩 가능
아래 코드처럼 두번씩 내보내기는 불가능
위의 코드에서 데이터 두개 이상을 내보내기 하는 법
var name1 = "kim" var name2 = "Lee" export default name1 export default name2
위의 코드 처럼export { name1, name2 };
{ }
로 오브젝트 처럼 내보내면 된다. 하지만, 이렇게 export로 내보내면 가져오기 할 때 변수명을 작명을 하지 못하고 변수명을 그대로 가져 사용해야한다.⇒ [export 변수명]은 변수명을 가져오는 거고import { name1, name2 } from "./data.js"; // export { name1, name2 } 을 import 할 경우
[export default { 데이터 } ]
형식은 변수명 없이 가져오는 거라 import 할때 작명 가능하다.
3.5.1. import 데이터 state 저장
import data from './data.js'
function(){
let [datas, datasEdit] = useState(data);
return(
<div>
{ name }
</div>
)
}
위의 코드 처럼 그냥 import 변수명을 적으면 된다.
4. Router
4.1. Routing
- App.js 파일
-
여러가지 태그들 import
다음
import { Link, Route, Switch } from 'react-router-dom';
를 추가한다.import ..... import { Link, Route, Switch } from 'react-router-dom'; function App(){ return ( <div> ... HTML ... </div> ) }
-
원하는 곳에 라우팅
function App(){ return ( <div> ... <Route path="/"> <div> 메인 페이지 </div> </Route> ... </div> ) }
주소에서 /로 들어가면 메인페이지
만약 path="/detail "이면 /detail로 접속시 그 route사이의 페이지가 나온다.
-
위에 처럼 path="/"
, path="/detail"
을 지정하면
detail 경로로 접속해도 디테일패치에 ' / '가 있기 때문에 '/'의 경로 내용이 보인다.
-
해결 방법
exact를 넣어주면 정확히 그 path의 내용과 일치할 때만 보여준다.
<Route exact path="/"> <div> 메인 페이지 </div> </Route> <Route path="/detail"> <div> detail 페이지 </div> </Route>
4.1.1. Route 쓰는 다른 방법
-
컴포넌트 보여주기
<Route path="/hello" component={Modal}></Route>
-
외부 컴포넌트 사용
5_component 파일 참조
<Route path="/hello"> <Detail/> </Route>
4.2. 페이지 이동
import { Link, Route, Switch } from 'react-router-dom';
위에서 추가한 import에 보면 Link가 있다
-
Link
<Link to ="/">Home</Link>
다음과 같이 Link태그를 사용할 수 있다.
<Link to = "경로">
⇒ Home을 클릭하면 해당 경로로 이동한다.
4.2.1. 페이지 이동 다른 방법
-
import추가
import { useHistory } from "react-router";
-
import를 추가하면 history를 사용가능
history ⇒ 이동했던 방문기록 등을 저장해 놓는 object
function Deatil(){ let history = useHistory(); return( <button className="btn btn-danger" onClick={ ()=>{ history.goBack() } }>뒤로가기</button> ) }
⇒ 뒤로가기 버튼을 누를시 history를 동작시킴
history.goBack()
→ 이 함수는 뒤로 가기 함수이다
이 history를 이용하면 커스텀해서 앞으로가기, 뒤로가기, 특정 경로로 이동하기가 가능
-
특정 경로로 이동하기
⇒
history.push('/경로')
4.3. Switch
Route path="/:id">
/:id
⇒ /모든문자
라는 뜻
만약 다음코드명
<Route path="/detail">
<detail/>
</Route>
<Route path="/:id">
<div> 아무거나 적을때 이것이 보임 </div>
</Route>
/detail
로 접속시에
아래 /:id
에 있는 '아무거나 적을때 이것이 보임'이것도 보여진다.
이런게 싫고 매칭이 된 것중 처음것만 보여주고 싶다면 Switch를 사용
-
Switch 사용법
-
우선 import 하기
1번 문항에서 import해서 가져 왔던 것중 Switch가 있다.
import { Link, Route, Switch } from 'react-router-dom';
다음과 같이 코드들을 감쌀 수 있다.
<Switch> ... <Route path="/detail"> <detail/> </Route> <Route path="/:id"> <div> 아무거나 적을때 이것이 보임 </div> </Route> ... </Switch>
⇒ '선택 하나 해주세요' 와 같다. (== 하나가 켜지면 하나가 꺼지는 것과 같음)
위에서는
/detail
과/:id
가 같이매칭이 된다.⇒ 위에서 중복 라우팅을 방지하기 위해서 사용한
exact
와 적절히 이용해서 라우팅에 사용 가능하다! -
4.4. URL 파라미터로 상세페이지 만들기
상품 페이지가 있고 각각의 상품 페이지를 클릭하면
/detail/상품번호
다음과 같이 이동한뒤 그 안에 데이터는 상품번호로 데이터를 바인딩해서
-
detail.js
function Detail(props) { return ( <p>{props.shoes[상품번호].title}</p> <p>{props.shoes[상품번호].price}원</p> ) }
위의 detail.js와 같은 코드를 만들 수 있다.
-
라우터 파라미터 받기
/경로
뒤에/:작명
을 하면 작명한 값을 그 라우터로 각각 값을 넘겨줄 수 있음// App.js 파일 <Route path="/detail/:id"> <Detail shoes={shoes} /> </Route>
⇒ 만약
/detail/12
을 접속하면 12을 전송시킴 -
입력받은 파라미터 전달하기
상단에
useParams
를 import한다.//detail.js 파일 import { useParams } from 'react-router-dom' function Detail(props) { let { id } = useParams(); return ( <p>{props.shoes[id].title}</p> <p>{props.shoes[id].price}원</p> ) }
let { 작명 } = useParmas();
를 하면→ 사용자가 입력한 URL 파라미터들이
→
{ 파라미터값 }
형식으로 중괄호로 쌓여있는채로 저장됨파라미터가 여러개 있으면
let = {id, id2, id3 } = useParams();
이런식으로 여러개로 작성하면됨⇒ 즉, 라우터로 다른 페이지 A를 만들어 놓고 그 페이지의 모양은 같고 데이터만 다를 경우 라우터로 페이지 번호를 파라미터로 전달해 주어서
⇒ 하나의 페이지에 데이터만 다르게 화면을 출력할 수 있다.
4.4.1. 파라미터 사용시 문제 해결
만약 App.js에서 데이터파일을 조작해서(=정렬과 같은) 데이터의 순서가 바뀔 경우 내가 클릭한 상품과 화면에 열어준 페이지의 파라미터의 값의 달라 다른 결과를 화면에 띄우게 된다.
-
예시
[A,B,C]의 파일이 있는데
App.js에서는 정렬을 통해
[C,B,A]가 되었고
나는 C를 클릭을 했지만 3번째 파라미터가 전달이 되면서 A가 뜨게 된다.
데이터에 상품의 영구 번호를 활용하자!
내가 데이터에 불러 올때 사용한 배열의 번호가 아니라 데이터 자체의 번호
다음 사진과 같이 상품 자체에 id값과 같이 번호를 주어서 저 번호를 그대로 사용하면된다.
-
해결 코드
다음과 같이
/:id
자리에 입력한 값과 영구번호가 같은{ 상품데이터 }
를 찾아서 데이터 바인딩을 해줌import React from 'react'; import { useHistory, useParams } from 'react-router-dom'; function Detail(props){ let { id } = useParams(); let 찾은상품 = props.shoes.find(function(상품){ return 상품.id == id }); return ( <h4 className="pt-5">{찾은상품.title}</h4> <p>{찾은상품.content}</p> <p>{찾은상품.price}원</p> ) };
let 찾은상품 = props.shoes.find(function(상품){ return 상품.id == id });
⇒ id값과 데이터의 id값이 같은 값을 찾은상품
으로 저장해주고 그 값으로 각각 데이터를 바인딩 시켜주면됨