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시 함게 설치 할 수 있다.
- 글로벌 설정 없이
화면 구성
📃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
로 또 다른 상위 컴포넌트의 구성요소로 사용 될 수 있다.
- 컴포넌트 사이를 연결하여 데이터 전송 등이 가능하게 해주는 저장공간 및 회로의 역할을 하는 것이
state
와props
이다.
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 형태로 작성했기 때문에 클래스 생명주기에 따라 생성 될 때 초기 값을 설정 할 수 있다.
- 보통
state
와props
,bind
를 세팅한다.
- state, props
state
는 현재 클래스의 상태 변수이다.- 때문에 사용 시
this.state.[변수명]
으로 사용한다. state
변수의 값을 변경 할 때는this.setState({변수명:값,변수명:값})
으로 변경한다.
- 때문에 사용 시
props
는 상위 클래스의 상태 변수를 하위 클래스에서 전달 받을 때 사용하는 변수이다.- 생성자의 매개변수로
props
를 받아야하며상위 클래스(컴포넌트)
에서하위 클래스(컴포넌트)
태그를 가져와 사용 할 때 값을 넘겨줘야 한다.
- 생성자의 매개변수로
props
랑state
를 뭐 리모컨이랑 뭐.. 어쩌구 뭐 이렇게 설명하던데 그냥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);
}
- functioin
- 함수다. 말할것도 없다.
- 컴포넌트를 클래스 형태 대신 함수형으로 선언 하여 사용 할 수 있다.
- 함수형과 클래스형 차이 참고 블로그 - 추천
- Class vs Function 생활코딩
function 사용
Class
와render()
사이에 선언해두고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>
);
}
render()
와return
사이에 선언해두고return
안에서 호출하여 사용
class ActionTest extends Component {
constructor(props){
...생성자...
}
render(){
function test(){
return "테스트";
};
return(
<div>{test()}</div>
);
}
- 해당
<div>
태그 위치에테스트
라는 글씨가 출력 된다.- 렌더링이 되면서 선언되기 때문에 컴포넌트 생성주기에 맞춰 생성 될 때랑은 차이가 있다.
- 뭔지는 잘 모른다 :)
- 함수형 컴포넌트 내부에서는
useState
를 임포트해서 사용 가능
- 렌더링이 되면서 선언되기 때문에 컴포넌트 생성주기에 맞춰 생성 될 때랑은 차이가 있다.
return
으로 알럿을 띄우는 등의 액션을 할 경우<div>
태그 없이{test()}
만 넣어도 된다.
- 태그 내부에 바로 이벤트 리스너 선언
<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 path
로url
을 입력해주면 정확히 똑같은 url이 아니면 매핑 되지 않음/
의 경우/blahblah
형식의 모든url
이 매핑 되기 때문
- Redirect
Redirect
태그 내부에 연결할url
을to
뒤로 작성- 예시에 나오듯이
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
위치에서 가져와state
의option
변수 값을 변경 한다.
조건부 렌더링
- 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>
);
}
반응형
'공부 기록' 카테고리의 다른 글
[JAVA] Spring Security Basic (0) | 2021.06.19 |
---|---|
[JAVA]J-Unit Test_Basic (0) | 2021.06.18 |
[디자인패턴]전략 패턴(Strategy Pattern) (0) | 2021.06.03 |
[디자인패턴]파사드 패턴(Facade Pattern) (0) | 2021.06.03 |
[디자인패턴] 데코레이터 패턴(Decorator Pattern), 옵저버 패턴(Observer Pattern) (0) | 2021.06.03 |
댓글