[React] 리액트 프로젝트 사용 기술 정리
React 프로젝트
사용한 기술 및 라이브러리
생겼던 문제들
이미지 용량 nginx
이모티콘 utf 처리
timezone
0. 기본 레이아웃 및 큰 컴포넌트
index/Root/App에서 Login or Dashboard로
0-1. React-router-dom
// Root.js
import {BrowserRouter} from “ React-router-dom “
<BrowserRouter>
<App/>
</BrowserRouter>
Q) 이렇게 한 이유 + react-router-dom이란? react, react-dom, reat-router-dom
Q) 컴포넌트란 ??리액트란??
Q) 리액트 기본 구조 이해하기
Class hello extend Component{
render(){
return();
}
}
export default hello
0-2. axios.defaults.baseURL='http://localhost:8080';
baseURL 제일 밖으로 빼놓음
0-3. index.js에서
serviceWorker.unregister();
이걸 resgister로 하면 서버 캐시 지워서 새로 들어갈때까지 이전 프로젝트 변경 전 모습으로 남아있음
Q) servicework - register, unregister란?
1. 로그인 컴포넌트 ( 대시보드 밖/ 안 따로 )
대시보드 밖 ( 로그인 전, storage에 token없음)
sign/Login
----/Logout
Q) sessionstorage, localstorage란? 나는 왜 토큰 session에 했지..?
Q) event.preventDefault()란?
이메일, 비밀번호 입력받아서 event.target.[name].value 에 따라서 focus()해주거나 검사하거나 ,, 로그인해주거나 함
axios.post로 formdata에 email, password값 보내고 token얻어와 sessionstorage에 저장하고 url /로 보내줌
Q)axios란? .then .catch란?
Q)this.props.history.push란?
Q)error.response status ,,
sign/PasswordUpd
----/signup
----/userList
----/CheckAuth
----/info
----/infoUpd
회원가입은 pw.match(정규식)이렇게 양식 비교해보고 중복확인은 버튼 누르면 check api보내는식으로 함
Q) react에 onchange, onclick, => handlechange, handleclick 바닐라자바스크립트로도 생각해보기
2. 관리자페이지 Dashboard
2.1 토큰검증
axios.interceptors.request.use(
config => {
if(config.url.match("dapi.kakao.com")){
config.headers['Authorization'] = 'KakaoAK ';
}
else{
const token = window.sessionStorage.getItem("jwtToken");
if (token) {
config.headers['Authorization'] = 'Bearer ' + token;
}
}
return config;
},
error => {
Promise.reject(error)
});
//Add a response interceptor
if(window.location.pathname!=="/user/login"){
axios.interceptors.response.use((response) => {
return response
}, function (error) {
if(error.response.status===404||error.response.status===500||error.response.status===409)return Promise.reject(error);
console.log(error.response);
if(error.response.status===403){
if(window.sessionStorage.getItem("jwtToken")!==null)
message.warning("토큰이 만료되어 로그아웃 됩니다");
window.sessionStorage.removeItem("jwtToken");
this.props.history.push('/user/login');
return Promise.reject(error);
}
});
}
axios.interceptors.request.use 를 이용해서 jw 토큰 넣어줬음
Q) 이 인터셉터 request, response 알아보기
2.2 eventListenr
window.addEventListener('resize', this.windowSize);
windowSize=e=>{
//화면 확대할때 side bar접히게
if(Math.round(window.devicePixelRatio * 100)>300){
this.setState({
collapsed:true,
})
}
else if(window.screen.width<=500){
this.setState({
collapsed:true,
})
}
else{
this.setState({
collapsed:false,
})
}
}
윈도우 사이즈 resize 될때 window.devicePixelRatio 또는 window.screen.width로 가로길이 잼
2.3. 코드 리뷰 받고싶은부분 ?
if(this.props.location.pathname.match("/web/notice")){
this.setState({
openKeys:['sub4'],
defaultKeys:['6'],
})
}
if(this.props.location.pathname.match("/wefl/user")){
this.setState({
openKeys:['7'],
defaultKeys:['7'],
})
}
네브바에 색이 칠해지는데 그게 새로고침을하고나면 초기화돼서 그거 지정해주려고 componentdidmount될때 url보고 지정해줬었음
이게 맞는건가!
그리고 원래는 뭐 location.어쩌고 바뀐거 적용했는데
componentDidUpdate(prevProps, prevState) {
const location = this.props.history.location;
const accessToken=window.sessionStorage.getItem("jwtToken");
if(prevProps!==this.props) {
if(location.pathname.match("store")){
this.setState({
openKeys:['1'],
defaultKeys:['1'],
})
}
if(location.pathname==="/user/info"){
this.setState({
openKeys:['sub5'],
defaultKeys:['8'],
})}
}}
componentDidupdate로 prevProps와 지금의 상태를 비교해서 다를때만 바꿔줄수있었음
Q) react life cycle?
ㅇㅇ
<Switch>
<Route exact path="/" component={this.state.isExpired?Logout:Main}/>
<Route exact path={["/store/list/","/store/list/:page","/store/insert","/store/update/:sid"]} component={this.state.isExpired?Logout:ManageStore} />
<Route exact path={["/store/detail/:sid","/store/payment/:sid" ,"/store/data/:sid","/store/webpage/:sid"
,"/store/log/:sid"]} component={this.state.isExpired?Logout:StoreDetail} />
<Route exact path={["/web/notice","/web/notice/insert","/web/notice/update/:id","/web/notice/detail/:id"]} component={this.state.isExpired?Logout:WebsiteManage} />
<Route exact path={["/wefl/user"]} component={this.state.isExpired?Logout:WeflUser}/>
<Route exact path={["/user","/user/info","/user/list"]} component={this.state.isExpired?Logout:Admin}/>
<Route exact path={["/check/wait/:page","/check/new/:page","/check/return/:page"]}component={this.state.isExpired?Logout:Check}/>
<Route exact path={["/check/detail/:status/:sid","/check/webpage/:status/:sid","/check/log/:status/:sid"]} component={this.state.isExpired?Logout:Detail}/>
<Route exact path={["/store/error","/check/error"]} component={this.state.isExpired?Logout:StoreError}/>
<Route component={this.state.isExpired?Logout:NotFound}/>
</Switch>
2.4
breadcrumb
const pathSnippets = window.location.pathname.split("/").filter(i => i);
const extraBreadcrumbItems = pathSnippets.map((_, index) => {
const url = `/${pathSnippets.slice(0, index + 1).join("/")}`;
return (
<Breadcrumb.Item key={url}>
{breadcrumbNameMap[url]}
</Breadcrumb.Item>
);
});
const breadcrumbItems = [
<Breadcrumb.Item key="main">
<Link to="/">위플</Link>
</Breadcrumb.Item>
].concat(extraBreadcrumbItems);
2.5
페이징 처리
totalsize, pagecount,
검색하고 삭제하는데 만약에 1페이지가 아닌 상태면 문제생기니깐 다 관리해줬음
다음매장잉 없으면 이전매장을 얻어온다음 그 이전매장의 페이지번호
if(res.data%this.state.pageSize===0) page = res.data/this.state.pageSize;
else page=Math.floor(res.data/this.state.pageSize)+1;
얻어오고 다음매장이 있으면 다음매장의 페이지번호얻어왔음
this.unlisten = this.props.history.listen((location, action) => {
원래 didupate하기전엔 이랬음
Q)queryString.parse location의 search랑 hash 차이
2.6. insert
처음엔 insertStore component불러와서 매장 정보 입력받고 그당므엔 insertWeb불러왔음
뒤로가도 남아있게 , 뒤로간다음 다시 돌아왔을때 남아있게 처리해주느게 어려웠음.
2.7 webpage hash
componentDidUpdate(prevProps,prevState){
if(prevProps!==this.props){
const anchor = this.props.history.location.hash.split('?')[0].split('#')[1];
if(anchor!==undefined&&anchor!==""){
const offset = document.getElementById(anchor).offsetTop;
window.scrollTo(0,offset-100);
}
const query = queryString.parse(this.props.history.location.hash.split('?')[1]);
if(query.key!==undefined){
this.setState({
searchKey:query.key,
searchValue:query.value,
})
}
}
}
----
예전에 적어둔거 발견해서 붙여넣는다..
- 바벨
: 바벨은 최신 자바스크립트 문법을 구형 브라우저에서도 돌 수 있도록 코드 자체를 변환시킨다.
- create-react-app
:페이스북은 쉽게 리액트 프로젝트를 셋업하고 바로 개발에만 집중할 수 있도록 도구를 만들었는데 그게 create-react-app이다.
npm install create-react-app으로 설치할 수 있다.
(yarn을 쓰는 사람들은 yarn을 써도 된다. yarn은 npm과 같이 자바스크립트 패키지 매니저다.
npm이 가진 이슈들을 해결하기 위해 페이스북, 구글 등이 힘을 합쳐 만든 새로운 자바스크립트 패키지 매니저다.)
create-react-app을 사용하면
‘create-react-app my_project’와 같이 순식간이 리액트로 된 페이지를 띄울 수 있는 구조가 만들어진다.
- 리액트 초반 필수 설치 라이브러리
react: 리액트를 사용하려면 당연히 리액트 라이브러리가 필요하지 않겠는가?
react-dom: 원래는 react에 함께 있었으나 이렇게 따로 떨어져 나왔다.
react와 DOM 사이에 연결해주는 역할을 한다.
react-scripts: 리액트 프로젝트 초기 셋업을 하는 것은 힘든 일이다. 그걸 보다 쉽고 간편하게 해준다.
babel-cli: 바벨을 터미널에서 사용하기 위해 필요하다. 바벨을 왜 쓰는지는 위에서 설명했다.
babel-preset-env: 바벨은 babel-preset-es2017과 같이 여러 버전이 있다. 딴거 말고 이거 깔면 알아서 해준다.
babel-preset-react: 바벨을 리액트에서 사용하게 해준다 . 우리는 리액트를 쓸거니까 이게 필요하다. 달리 말하면 바벨과 리액트는 별개 프로젝트다.
webpack: 웹팩을 쓰기 위해 필요하다.
babel-core: 웹팩용 바벨(?)이다. 터미널에서 쓸 때 babel-cli를 썼는데 이걸 웹팩에서 사용하는 용도다.
babel-loader: 웹팩에서 바벨을 로드할 때 이 로더를 쓴다.
@ cors 오류
- import react
파일에서 JSX 를 사용하려면, 꼭 React 를 import 해주어야 합니다. ( import 를 하는 것은, 우리가 webpack 을 사용하기에 가능한 작업입니다. )
---
index.js에
ReactDOM.render(<App />, document.getElementById('root'));
DOM id가 root인애를 public/index.html에서 찾아서 거기에다가 App을 그리도록 하는거
```
import React ,{Component} from 'react';
class App extends Component {
render(){ //클래스 형태의 컴포넌트에는 꼭 render함수가 있어야함
return ( //그 내부에서는 jsx리턴
<div>
hello my name is kangjisu
</div>
);
}
}
export default App; //우리가 작성한 컴포넌트를 다른 곳에서 불러와 사용할 수 있도록 내보내기
```
-두개이상의 엘리먼트는 무조건 하나의 엘리먼트로 감싸져있어야함.
=>이때 Fragment 사용 (import {Fragment} from 'react'해주어야함)
```
import React, { Component } from 'react';
class App extends Component {
render() {
const name = 'react';
return (
<div>
hello {name}!
</div>
);
}
}
export default App;
```
값을 바꿔줘야할땐 let, 고정되면 const
```
import React, { Component } from 'react';
class App extends Component {
render() {
const value = 1;
return (
<div>
{
(() => {
if (value === 1) return (<div>하나</div>);
if (value === 2) return (<div>둘</div>);
if (value === 3) return (<div>셋</div>);
})() // 화살표함수. this,arguments,supe개념이 없는 익명함수
}
</div>
);
}
}
export default App;
```
{/* */} 주석은이렇게
# 4편 :: props 와 state
props 는 부모 컴포넌트가 자식 컴포넌트에게 주는 값. 자식컴포넌트에서는 props를 받아오기만 하고 수정할 수 없음
state 는 컴포넌트 내부에서 선언하며 내부에서 값 변경 가능
#5편
componentDidMount() {
// 외부 라이브러리 연동: D3, masonry, etc
// 컴포넌트에서 필요한 데이터 요청: Ajax, GraphQL, etc
// DOM 에 관련된 작업: 스크롤 설정, 크기 읽어오기 등
}
컴포넌트가 화면에 나타나게 됐을때 호출 , 필요데이터 요청위해 axios,fetch등을 통하여 ajax요청이나 돔 속성 읽거나 변경하는 작업 진행
#7편 배열다루기
리액트애서는 state 내부의 값을 직접적으로 수정하면 절대로 안됩니다. 이를 불변성 유지라고 하는데요, push, splice, unshift, pop 같은 내장함수는 배열 자체를 직접 수정하게 되므로 적합하지 않습니다.
그 대신에, 기존의 배열에 기반하여 새 배열을 만들어내는 함수인 concat, slice, map, filter 같은 함수를 사용해야합니다.
용어
-파싱
0렌더링
---
공부순서
팁탭토->https://velopert.com/3480->https://velopert.com/3486
---
AWS, ec2 , nginx 공부 (날개의 노트 사이트 https://wingsnote.com/ 참고)
- EC2 : 가상의 컴퓨터(ex:서버) 만들고 관리하는 서비스
- 인스턴스 : EC2에서 만드는 가상의 컴퓨터 하나 ( 실제 컴퓨터의 OS가 아닌 EC2에서 지원해주는 OS사용)
- 인스턴스 타입 : 사양을 의미
- AMI : 미리 만들어둔 아마존 가상 머신의 이미지
- AWS는 EC2인스턴스를 만들때 완전 빈 가상 컴퓨터가 아닌 최소한 이미 만들어진 OS가 설치돼있는 이미지 설치
MyAMIs : 유저가 만든거
- 가상화 타입 (HVM vs Paravirtualization)
- HVM : 안정성 HIGH 성능 LOW
Paravirtualization : 안정성 LOW 성능 HIGH // 두개 비교해서 상대적으로 보면 이렇다는느낌~
- 인스턴스 스토리지 : cdrive느낌 (휘발성이므로 ami,스냅샷 만들어줘야 안날라감)
- EBS : 외장 HDD느낌 .지워지면 안되는 데이터들은 이거로 보통. (micro는 ebs)
- EC2인스턴스는 보안을 위해 id/pw가 아닌 key 파일을 이용해 접속한다. -> ---.pem파일 (노출안되게 조심!!)
- SSH: secure shell protocol
:컴퓨터가 public network를 통해 통신할 때 보안상 안전하게 해주는 protocol
- NGINX : 경량 웹서버 (아파치같은거.. 아파치는 프로세스와 쓰레드 기반, NGINX는 비동기이벤트방식으로 요청 처리 )
: 모바일 서비스 쪽에 많이 쓰임
- EC2 인스턴스 보안 그룹 설정 : 기본 SSH접근은 22. 웹 브라우저 가능하려면 HTTP 포트 80 설정 해주어야함