기타/FE

[React] 리액트 프로젝트 사용 기술 정리

지수쓰 2020. 6. 9. 15:57
반응형

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 설정 해주어야함