본문 바로가기
공부 기록

[REACT]30분만에 대충 보고 당장 써보는 리액트

by 타태 2021. 6. 7.

2021.05.25 - [인턴업무] - [AXIOS] Ajax를 Axios로 변환하기

30분 정도 쓱 보고 바로 대충 써볼 수 있는 리액트

 

- 인턴 업무의 일환으로 react를 사용하면서 가장 기본적인 부분들을 대충 쓰윽 보고 아 그렇구나~ 할 수 있도록 작성했다.

- 아주 조금의 프론트 지식이 선행 되어야 한다.

- 나도 잘 모르기 때문에 내가 아는 선에서 얼렁뚱땅 넘어가는 것도 있다.

- Redux는 쓰고 있긴 한데 다른 인턴분이 적용하셔서 포함하지는 못했다. 하지만 이것도 당장 쓰기에는 그렇게 어렵지 않다.

 

📚목차
1. 리액트 구조
2. 클래스, 변수, 함수 선언
3. jQuery
4. Axios
5. Router
6. ETC

 

1. 리액트 구조

프로젝트 구성

📃pacakge.json
  • Maven에서의 pom.xml과 같은 녀석
  • 프로젝트 이름, 버전 - 명령어 - 설정 - 의존성 등을 관리하고 설정 할 수 있다.
{ //프로젝트 정보
  "name": "frontend",
  "version": "0.1.0",
  "private": true,
      //의존성 및 버전 정보
  "dependencies": {
    "@testing-library/jest-dom": "^5.12.0",
    "@testing-library/react": "^11.2.7",
    "@testing-library/user-event": "^12.8.3",
    "axios": "^0.21.1",
    "jquery": "^3.6.0",
    "material-ui": "^0.20.2",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-router-dom": "^5.2.0",
    "react-scripts": "4.0.3",
    "web-vitals": "^1.1.2"
  },
      //스크립트 명령어 정보
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
      //ESLint 설정 정보
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
      //CORS 해결을 위한 방법 중 하나인 proxy 설정(* 기본 설정 아님)
  "proxy": "http://localhost:8888",
      //브라우저 환경 설정 정보
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

 

📂node_module
  • maven repository 같은 녀석
  • 설치되어 있는 의존성, 라이브러리들이 저장 되는 곳
  • npm install 할 때 -g 옵션을 주면 maven의 .m2 폴더와 같이 전역 설치가 된다.
    • 글로벌 설정 없이 i == install할 경우 프로젝트 디렉토리 밑의 ./node_module 에 라이브러리가 저장 된다.
    • -s == --save 옵션을 주면 package.json에 해당 의존성 설정이 저장 되어 node_module 없이 프로젝트를 저장하거나 전송하더라도 intall시 함게 설치 할 수 있다.

글로벌 설치 VS 로컬 설치 참고 블로그

 


 

화면 구성

📃public/index.html
  • SPA (Single Page Applicatioin) 제공을 위해 유일하게 사용 되는 html 페이지
  • 다른 내용은 없고 <body> 태그의 id가 "root"

 

📃src/index.js
ReactDOM.render(
    //<React.StrinctMode>는 기본 설정 x

  <React.StrictMode>
    <BrowserRouter>
    <App />
    </BrowserRouter>
  </React.StrictMode>,
  document.getElementById('root')
);
  • id 값이 "root"인 태그를 가져오는 내용의 ReactDOM.render 함수 사용
    • <App/> 컴포넌트의 내용을 index.html 화면에 출력한다

 

  • <StrincMode>
    • 개발 모드에서만 적용 되는 검사 도구로, 안전하지 않은 생명주기를 사용하는 컴포넌트를 발견해 준다.

 

📃App.js
import { Component } from 'react';
import './App.css';

class App extends Component {
  }

  render () {
    return (
             ...내용...
    );
  }
}

export default App;
  • react 프레임워크로부터 Component를 임포트 한 뒤 이를 상속 받은 App Class를 정의
    • index.js에서 호출 되어 index.html에 뿌려지는 부분이다.
    • 최상위 컴포넌트

 

📑component

컴포넌트

 

  • 회로 기판 위에 올라가는 구성 요소들을 Component라고 한다.
  • 회로 기판이 App.js고 이 회로 기판에 올라가서 화면을 구성하는 요소들을 Component라고 할 수 있다.
    • App.js조차 Component를 상속 받아 구현하는 하나의 Component로 또 다른 상위 컴포넌트의 구성요소로 사용 될 수 있다.
  • 컴포넌트 사이를 연결하여 데이터 전송 등이 가능하게 해주는 저장공간 및 회로의 역할을 하는 것이 stateprops이다.

 


 

2. 클래스, 변수, 함수 선언

//Component를 만들게 되면 React와 Component를 import해야 한다.
import React, { Component } from 'react';

class AccessControlTest extends Component {
  constructor(props){
    super(props);
    this.state={
     option:'view',
     userId:this.props.userId
    }
    this.hadleChange = this.hadleChange.bind(this);
  }

  hadleChange(e){
    this.setState({option:e.target.value});
  }

  render() {
      return (
          <div>
              ... 내용 ...

          </div>
    );
}
// export를 설정하여 다른 컴포넌트에서 import 하는 이름을 선언
// default는 하나만 설정 가능
export default AccessControlTest;
위 예제를 이용하여 설명하겠다.
  • Constructor
    • 잘 알다시피 생성자다.
    • 컴포넌트를 Class 형태로 작성했기 때문에 클래스 생명주기에 따라 생성 될 때 초기 값을 설정 할 수 있다.
    • 보통 stateprops, bind를 세팅한다.
  • state, props
    • state는 현재 클래스의 상태 변수이다.
      • 때문에 사용 시 this.state.[변수명]으로 사용한다.
      • state 변수의 값을 변경 할 때는 this.setState({변수명:값,변수명:값})으로 변경한다.
    • props는 상위 클래스의 상태 변수를 하위 클래스에서 전달 받을 때 사용하는 변수이다.
      • 생성자의 매개변수로 props를 받아야하며 상위 클래스(컴포넌트)에서 하위 클래스(컴포넌트) 태그를 가져와 사용 할 때 값을 넘겨줘야 한다.
    • propsstate를 뭐 리모컨이랑 뭐.. 어쩌구 뭐 이렇게 설명하던데 그냥 state는 내거 props는 아빠거 이렇게 생각하자
App.js에서 LoginBox.js 컴포넌트로 state넘겨주는 예시
<LoginBox userId={this.state.userId} 
            onChangeMode={function(_userId,_userName,_url,_loginedIn){
                    this.setState({
                      userId:_userId,
                      userName:_userName,
                      url:_url,
                      loginedIn : _loginedIn
                    })   

                }.bind(this)}></LoginBox>

 

LoginBox.js 컴포넌트에서 App.js로 props 넘겨주는 예시
Function (){
    this.props.onChangeMode(this.state.userId,this.state.userName,this.state.url,this.state.loginedIn); 
    }
  • LoginBox.js 컴포넌트의 state값을 상위 컴포넌트의 함수를 호출하여 매개변수로 사용.
    • 생성자를 통해 연결 된 props를 통해 호출한다.

 

  • bind(this)
    • 함수가 현재 클래스 내부에서만 사용 될 경우 this와 묶어줄 필요 없다.
    • .bind(this)를 이용해 해당 클래스와 묶어주면 생성자가 정의한 state값을 연결하여 사용 할 수 있어진다.
    • 미리 묶어주면 매번 함수에 직접 선언하지 않아도 된다.

 

생성자에서 bind 미리하기 예시
class AccessControlTest extends Component {
  constructor(props){
    ...생성자...
    }
    // 함수 미리 묶어두기     
    this.handleChange = this.handleChange.bind(this);
  }

 

function 사용

  1. Classrender() 사이에 선언해두고 return안에서 {this.함수명}으로 호출하여 사용
class ActionTest extends Component {
    constructor(props){
        ...생성자...
    }
handleChange(e){
    this.setState({option:e.target.value});
  }
        render(){
            return(
                <select value={this.state.option} onChange={this.handleChange}>
                    <option value="옵션">옵션</option>
                    <option value="옵션">옵션</option>
                </select>
            );
        }

 

  1. render()return 사이에 선언해두고 return안에서 호출하여 사용
class ActionTest extends Component {
    constructor(props){
        ...생성자...
    }
        render(){
                function test(){
                  return "테스트";
                };
            return(
                <div>{test()}</div>
            );
        }
  • 해당 <div> 태그 위치에 테스트라는 글씨가 출력 된다.
    • 렌더링이 되면서 선언되기 때문에 컴포넌트 생성주기에 맞춰 생성 될 때랑은 차이가 있다.
      • 뭔지는 잘 모른다 :)
      • 함수형 컴포넌트 내부에서는 useState를 임포트해서 사용 가능
  • return으로 알럿을 띄우는 등의 액션을 할 경우 <div>태그 없이 {test()}만 넣어도 된다.

 

  1. 태그 내부에 바로 이벤트 리스너 선언
<input type="button" id="button" value="실행"  onClick={function(e){
                           e.preventDefault();
                           ...함수 선언...
                         }/*.bind(this)*/} />
  • 이 경우 함수의 인자로 event가 항상 넘어온다.
    • event.preventDefualt();를 이용해 기본 기능(submit, anchor tag)을 막을 수 있다.
    • e.target.value에서 이벤트를 통해 넘어온 Input태그의 값을 꺼내 올 수 있다.
    • 위에서 설명한 대로 해당 함수 내부에서 state등을 사용한다면 .bind(this)를 달아주어야 한다.

 


3. jquery

App.js
import jQuery from 'jquery';window.$ = window.jQuery = jQuery;
  • Apps.js에서 jQuery를 임포트
    • 모든 임포트 후 마지막에 window.$ = window.jQeury = jQeury; 선언
    • 이후 하위 컴포넌트들에서 window.$('선택자').함수(); 형태로 사용 가능

 


 

4. Axios

  • 비동기 통신을 위해 사용하는 모듈, React 사용자들이 선호 함

 

간략한 API 호출 방식
axios.get(url[, config])            // GET
axios.post(url[, data[, config]])   // POST
axios.put(url[, data[, config]])    // PUT
axios.patch(url[, data[, config]])  // PATCH
axios.delete(url[, config])         // DELETE

axios.request(config)
axios.head(url[, config])
axios.options(url[, config])
  • 기본적으로 첫 번째 인자는 URL, 두 번째 인자는 config
    • 데이터 전송이 필요 한 경우는 첫 번째 인자는 URL, 두 번째 인자는 data 세 번째 인자는 config

 

jQuery와 Axios 활용 예제

ContentTest.js
import React, { Component } from 'react';
import axios from 'axios';

class ContentTest extends Component {
  render() {
    return (
      <pre className="showLabs">{this.props.subtitle}
        <br/>
        ID <input type="text"  id="user_id"/>
        PASSWORD<input type="password" name="passwd"  id="user_pw"/>
        <input type="button" value="실행" 
            onClick={function(e){
              e.preventDefault(); 
              var _id = window.$("#user_id").val();
              var _pw = window.$("#user_pw").val();
                    
              window.$('#result').empty();
                    
              axios.post('/[URL]', null, {params : {
                id : _id,
                pw : _pw
              }})
              .then((Response)=>{       	    		             
                window.$('#result').append(Response.data); 
              })
              .catch(() => {   
                window.$('#result').append("요청처리 실패"); 
              });
            }} />
      </pre>
    );
  }
}
  export default ContentTest;

 

GET - 호출만 할 경우
// ID로 사용자 요청
axios.get('/user?ID=12345')
  // 응답(성공)
  .then(function (response) {
    console.log(response);
  })
  // 응답(실패)
  .catch(function (error) {
    console.log(error);
  })
  // 응답(항상 실행)
  .then(function () {
    // ...
  });

 

GET - 데이터를 전송할 경우
axios.get('/user', {
    params: {
      ID: 12345
    }
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  })
  .then(function () {
    // ...
  });

 

POST
axios.post('/user', {
    firstName: 'Fred',
    lastName: 'Flintstone'
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

 

  • jQuery를 사용할 때 전송이 제대로 되지 않는 경우가 있음 이럴 경우 두 번째 인자를 null로 주고 세 번째 인제에 params를 주면 가능
axios.post('/user', null, {prams:{
    firstName: 'Fred',
    lastName: 'Flintstone'
  }})
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

 

Multi Request
function getUserAccount() {
  return axios.get('/user/12345');
}

function getUserPermissions() {
  return axios.get('/user/12345/permissions');
}

axios.all([getUserAccount(), getUserPermissions()])
  .then(axios.spread(function (acct, perms) {
    // Both requests are now complete
  }));

 

Axios form
axios({
    url : '/url/path',
    method : 'post',
    data:{
        data:data
    }
	})  
    	.then((Response)=>{       	    		             
        	window.$('#result').append(Response.data); 
    })
        .catch(() => {   
        	window.$('#result').append("요청처리 실패"); 
    });
    }}
  • 위와 같은 형식으로도 사용 가능

 

Axios 객체 생성 및 호출 과 Interceptor
const instance =axios.create({
    baseUrl: 데이터를 요청할 기본 주소,
    timeout : 1000 (변경 가능)
};

============================
// axios request 처리
instance.interceptors.request.use(
  function (config) {
    config.headers["Content-Type"] = "application/json; charset=utf-8";
    config.headers["Authorization"] = " 토큰 값";
    return config;
  },
  function (error) {
    console.log(error);
    return Promise.reject(error);
  }
);

// axios response 처리
instance.interceptors.response.use(
  function (response) {
    console.log(response);

    return response.data.data;
   
  },
  function (error) {
    errorController(error);
  }
);

// 다른 파일에서 호출하여 사용
login(data) {
  return ApiController({
    url: "login",
    method: "post",
    data: data,
  })

};

// api 사용
modifyBoardContent(data) {
    var params = {
        boardNo: data.boardNo,
        boardTitle: data.boardTitle,
        context: data.context,
        userNo: AuthService.getUserNo()
    };

    return ApiController({
        url: base + "modify",
        method: "put",
        data: params,
    });
}
  • Axios 객체 생성 후 이를 이용 한 Interceptor 기능을 사용

코드 출처 및 참고 블로그

 


 

5. Router

1. 기본 Route 태그 사용 법
import Route from 'react-router-dom';

class App extends Component{
render () {
    return (
      <Route path="/sign" component={Sign}/>
    	);
    }
}


export default App;
  • <Route>태그 내부에 url과 매핑해줄 component 작성

 

2. Route 받는 컴포넌트 내부에 props/state 전달 할 경우
import Route from 'react-router-dom';

class App extends Component{
render () {
    return (
        <Route path="/test/propsTest" >
            <propsTest userId = {this.state.userId}></propsTest>
        </Route>
    	);
    }
}


export default App;
  • <Route>태그 내부에 url 작성
    • 태그 하위에 컴포넌트 태그 작성

 

3. 쿼리 전달 받는 경우
import Route from 'react-router-dom';

class App extends Component{
render () {
    return (
        	<Route path="/test/:Id" component={ParamTest}/>
    	);
    }
}


export default App;
  • <Route>태그 내부에 url과 매핑해줄 component 작성
    • url 작성 시 /:변수형태로 연결

 

쿼리 받는 쪽
import React from 'react';

const ParamTest = ({match}) => {
    return (
        <div>
            <h2>Param : {match.params.userId}</h2>
        </div>
    );
};

export default ParamTest;
  • match에 담겨 넘어온 params에서 전달 된 변수를 꺼내어 사용

 

4. Exact path _ Redirect _ Switch _ Link to
import {Redirect, Route, Switch} from 'react-router-dom';

export default  class App extends Component{
    Constructor(props){
        super(props);
        this.state={
            loginedIn:this.props.loginedIn
        }
    }
render () {
    return (
 			<Route exact path="/">
                <Main></Main>
                <LoginBox userId={this.state.userId} onChangeMode={function(_userId,_userName,_url,_loginedIn){
                    this.setState({
                      userId:_userId,
                      userName:_userName,
                      url:_url,
                      loginedIn : _loginedIn
                    })   
                 }.bind(this)}></LoginBox>
                  
                {this.state.loginedIn ? <Redirect to ="/redirectUrl"> : <Redirect to ="/"/>}
            </Route>
        <Switch>
            <Route path="/extra/:name" component={Extra}/>
            <Route path="/extra" component={Extra}/>
        </Switch>
    	);
    }
}
  • Exact path
    • <Route>태그 내부에 exact pathurl을 입력해주면 정확히 똑같은 url이 아니면 매핑 되지 않음
      • / 의 경우 /blahblah 형식의 모든 url이 매핑 되기 때문
  • Redirect
    • Redirect 태그 내부에 연결할 urlto 뒤로 작성
    • 예시에 나오듯이 Redirect할 곳을 삼항 조건식을 이용하여 설정 할 수 있음
  • Switch
    • 중복 되는 url을 가진 경우 Switch태그 하위에 작성하여 위에서부터 아래로 진행 될 수 있도록 순서를 정할 수 있다.
    • 예시에서 나오듯이 파라미터 값을 전달 받을 경우가 위에 있어야 파라미터를 전달 받을 수 있음
      • 아니면 /extra/:name보다 먼저 나오는 /extra로만 매핑 되기 때문에 파라미터를 받을 수 없음
  • Link to
<div>
    <ul>
        <li><Link to="/">Home</Link></li>
        <li><Link to="/about">About</Link></li>
        <li><Link to="/about/foo">About Foo</Link></li>
    </ul>
    <hr/>
</div>
  • Router로 이동하기 위해서는 <a href="/"></a>와 같은 앵커태그가 아닌 Link to를 사용해야 한다.

라우터 참고 블로그 - 추천

 


 

6. ETC

radio-button
import React, { Component } from 'react';
import axios from 'axios';

class radioButtonTest extends Component {
  constructor(props){
    super(props);
    this.state={
      inputStatus : 'radio_3'
    }
  }
  render() {
    return (
              <div id="content">

                    <label htmlFor='radio'>선택 1</label>
                   <input type="radio" id='radio' 
                   checked={this.state.inputStatus === 'radio_1'}
                   onChange={() => this.setState({inputStatus:'radio_1'})}/>
                  <br/> 
            
                  <label htmlFor='radio'>선택 2</label>
                   <input type="radio" id='radio' 
                   checked={this.state.inputStatus === 'radio_2'}
                   onChange={() => this.setState({inputStatus:'radio_2'})}/>
                  <br/> 
            
                  <label htmlFor='radio'>선택 3</label>
                   <input type="radio" id='radio' 
                   defaultChecked
                   checked={this.state.inputStatus === 'radio_3'}
                   onChange={() => this.setState({inputStatus:'radio_3'})}/>
                  <br/> 
             </div>
    );
  }
}
  export default radioButtonTest;
  • Input태그 사이에 문자를 입력 할 수 없기 때문에 label을 달아서 글자를 표시 한다.
  • 기본 체크는 defaultChecked를 속성으로 넣어준다.
  • inputStatus 변수 값과 미리 설정해둔 이름이 같을 경우 체크 된다.
  • 라디오 버튼이 클릭 되었을 경우 inputStatus 변수 값을 변경 해 준다.

 

select-option
import axios from 'axios';
import React, { Component } from 'react';

class SelectTest extends Component {
  constructor(props){
    super(props);
    this.state={
     option:'type'
    }
    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(e){
    this.setState({option:e.target.value});
  }

  render() {
    return (
  
      <div id="content">
                <pre>
                  작업선택:
                  <select  value={this.state.option} onChange={this.handleChange} name="data"  id="data5">
                    <option value="type" >--- show txt ---</option>
                    <option value="dir" >--- show Dir ---</option>
                  </select>
                </pre>
        </div> 
    );
  }
}
  export default SelectTest;
  • selsect 태그의 value 속성을 option 변수로 설정한다.
  • 선택이 변경 되었을 경우 onChange 이벤트로 인해 handleChange 함수가 호출 된다.
  • handleChange함수는 이벤트가 발생하며 가져온 값을 event.target.value위치에서 가져와 stateoption 변수 값을 변경 한다.

 

조건부 렌더링
  • if-else
  constructor(props){
    super(props);
    this.state={
     userId:this.props.userId
    }
render() {
    if(this.state.userId === 'admin'){
      return (
	  <ForAdmin></ForAdmin>
    );
      }else{
      return (
      <ForNotAdmin></ForNotAdmin>
    );
	}
}   

 

  • 삼항 연산자
  constructor(props){
    super(props);
    this.state={
     userId:this.props.userId
    }
render() {
      return (
        <div>{(this.state.userId === 'admin') ? (<ForAdmin/>) : (<ForNotAdmin/>)}</div>
      );
}

 

조건부 렌더링 참고 블로그 - 추천


 

반응형

댓글