componentDidMount(){
//ajax 요청 객체 생성
let request = new XMLHttpRequest()
//요청 준비
request.open('GET', "http://127.0.0.1/todo?userid=Django")
//요청
request.send('')
//응답 처리
request.addEventListener('load', () => {
//json 데이터 출력
console.log(request.responseText)
})
}
구동 http://localhost:3000/
CORS Policy 에러가 출력
서버 애플리케이션은 127.0.0.1:80으로 실행 중이고 클라이언트 애플리케이션은 localhost(127.0.0.1):3000으로 실행중
SOP (동일 출처 정책)
ajax나 fetch api는 브라우저의 동일 출처 정책에 따라 자신과 동일한 도메인의 데이터만 받아올 수 있다.
동일 도메인이란 IP주소와 포트번호까지 일치하는 것을 의미한다.
서버 애플리케이션과 클라이언트 애플리케이션을 따로 구현하면 SOP 정책에 따라 ajax나 fetch api를 이용해서는 서버의 데이터를 사용할 수 없다.
서버 애플리케이션에서 요청이 가능한 클라이언트 애플리케이션의 도메인을 등록
서버 애플리케이션을 만들 때 CORS 설정을 확인해두자!
* React의 경우는 react의 설정 파일에 설정을 해도 CORS 설정이 가능하다.
* react가 node.js 플랫폼 위에서 동작하는데 node.js가 C/C++이라서 proxy를 이용해 react에 데이터를 넘겨줄 수 있다.
componentDidMount(){
//ajax 요청 객체 생성
let request = new XMLHttpRequest()
//요청 준비
request.open('GET', "http://127.0.0.1/todo?userid=Django")
//요청
request.send('')
//응답 처리
request.addEventListener('load', () => {
//json 데이터 출력
//JSON 문자열을 데이터로 변환
let data = JSON.parse(request.responseText);
console.log(data)
//서버에서 받아온 데이터를 state에 대입해서 화면에 출력
this.setState({items:data.list})
})
}
이전의 애플리케이션들은 여러 개의 HTML 파일을 만들어서 화면 전환을 이용해서 여러 콘텐츠를 출력했는데 -> 화면 전환을 하게 되면 이전 내용을 삭제하고 새로운 내용을 출력해야 하기 때문에 깜빡임이 발생하고 -> 네트워크 에러가 발생하게 되면 화면 전체가 에러 페이지를 출력 -> 모바일의 경우는 에러 페이지를 보는 횟수가 증가
해결 방법으로 로컬에 데이터를 저장해서 네트워크 에러가 발생한 경우 로컬의 데이터를 출력 하나의 화면을 여러 컴포넌트로 분할하고 분할한 컴포넌트 별로 별도로 데이터를 요청해서 출력
SPA를 만들기 위한 프레임워크로 널리 사용되는 것이 angular, react, vue 입니다.
angular는 구글이 만든 것으로 공식적으로 더 이상 업데이트를 하지 않는다고 발표를 했습니다.
현재 국내 플랫폼 기업이나 중소 기업은 react를 선호하는데 vue를 사용하는 곳도 있습니다.
2) React
2013년, Facebook에서 발표한 SPA를 구현하기 위한 오픈소스 자바스크립트 프레임워크
새로운 문법 사용: 가상 DOM과 JSX
출력이 빠름: 게임 엔진의 출력 방식을 이용, 가상의 DOM을 메모리에 배치하기 떄문
컴포넌트 기반
태그 화면에 보여지는 개체 <div>
컴포넌트 하나의 영역을 나타내기 위한 태그와 코드의 집합 자체적으로 데이터를 가질 수 있고, 데이터가 변경되면 자동으로 재출력 (새로고침 필요 X) 미리 구조를 만들어두고 다시 출력할 때는 변경된 부분만 다시 출력
프레임워크가 제공하는 기능을 그대로 사용
클래스가 충분한 기능을 제공해주기 때문에 클래스를 이용해서 인스턴스를 만들어서 바로 사용
ex. 프레임워크가 Template라는 클래스를 제공하면 template = new Template()
프레임워크가 제공하는 기능을 상속받아서 재정의해서 사용
클래스가 충분한 기능을 제공해주지 않아서 내가 기능을 추가해서 사용
상속을 받으면 상위 클래스의 모든 것을 하위 클래스가 물려받음
React에서는 Component라는 클래스가 Component의 기능은 전부 가지고 있는데 화면에 아무것도 출력하지 않는다. React.Component로부터 상속을 받고 render라는 메서드를 재정의해서 return 값을 출력하도록 설계
React-native
- 모바일 앱을 만들 수 있다.
- 안드로이드와 애플 환경에서 모두 사용할 수 있게 코드를 바꿔준다.
Figma
- 디자인을 리액트 코드로 바꿔준다.
3) 설치
node.js 설치
- node.js를 자바스크립트로 애플리케이션을 개발하기 위한 플랫폼이다. (프레임워크 아님)
- 설치확인: node --version
패키지 관리자: npm과 yarn
- package.json 파일에 의존성을 설정하고 node.modules 디렉토리에 패키지 저장
- git hub에 업로드 할 때 node_modules는 할 필요 없음. package.json만 있으면 빌드를 다시 해서 설치 가능
npm install --location=global yarn
- 설치 확인: yarn --version
4)React 프로젝트 생성 및 실행
생성
yarn create react-app 앱이름(myapp)
실행
#myapp 디렉토리에서
yarn start
yarn 없이 실행: npm start
5) Comonent를 화면에 출력
Component: 화면에 출력되는 독립적인 개체
src 디렉토리에 ToDo.jsx
확장자는 js 도 상관없지만 react 컴포넌트 파일이라는 것을 알려주기 위해서 jsx 로 설정
import React from "react";
//react에서 컴포넌트 클래스를 만들기 위해 Component로부터 상속 받기
class ToDo extends React.Component {
//화면에 출력할 내용을 리턴하는 메소드
render(){
return(
<div className="ToDo">
<input type="checkbox" id="todo0" name="todo0" value="todo0"/>
<label for="todo0">ToDo 컴포넌트 만들기</label>
</div>
)
}
}
id: 자바스크립트에서 태그를 구별해서 가져오기 위한 값 (중복 불가) document.getElementById
class: react에선 className. css에서 동일한 디자인을 적용하기 위한 이름 (중복 가능) document.getElementByClassName
name: 클라이언트가 서버로 전송할 때 이름 (중복 가능. checkbox, select 등)
value: 값
label: for="id" 글자를 눌러도 체크가 된다.
메인 페이지의 역할을 수행하는 App.js 수정해서 ToDo 컴포넌트 출력
import './App.css';
import React from "react"
import ToDo from "./ToDo" #파일 이름이라는 것을 강조하기 위해 ./ 사용, 없어도 됨
function App() {
return (
<div className="App">
<ToDo />
</div>
);
}
export default App;
export default App; 이 없을 경우 에러 ERROR in ./src/index.js 12:33-36 export 'default' (imported as 'App') was not found in './App' (module has no exports)
javascript는 기본적으로 private이라서 그렇다.
react는 App.js 파일이 전체 화면을 출력하는 파일 App.js에 작성한 내용이 출력 react는 반드시 하나로 묶어서 출력해야 함
import React from "react"
class Sample extends React.Component{
render(){
return(
<div className="Sample">
<p>안녕하세요</p>
</div>
)
}
}
export default Sample;
App.js
import './App.css';
import React from 'react';
import ToDo from './ToDo';
import Sample from './Sample';
function App() {
return (
<div className="App">
<ToDo />
<Sample/>
</div>
);
}
export default App;
6) 컴포넌트에서 데이터를 사용하는 방법
props 속성 : 상위 컴포넌트에서 넘겨주는 데이터 큰 화면에서 작은 화면으로 넘어갈 때 전달해주는 데이터 내가 쓸 데이터를 내가 만들어서 준다.
state 상태 : 컴포넌트 내부에서 사용하는 데이터 react는 props나 state에 변화가 생기면 화면을 다시 출력
context : 글로벌·전역변수, 모든 컴포넌트에서 사용할 수 있는 데이터 ex. 로그인 기능
redux : 전역 데이터를 만드는 외부 라이브러리
Entry 포인트 : React는 시작점이 App.js
7) props와 state 사용
ToDo.jsx
import React from "react"
class ToDo extends React.Component{
//생성자
constructor(props){
super(props); //상위 클래스에서 넘겨준 모든 props를 현재 클래스에 저장
//state 생성 - item이라는 이름으로 props 중에서 item이라는 값을 state로 저장
//props는 상위 컴포넌트에서 전달한 데이터라서 읽기는 가능하지만
//수정이나 삭제가 안되므로 수정이나 삭제를 하고자 하는 경우는
//state로 변환을 해야 합니다.
this.state = {item:props.item}
}
render(){
return(
<div className="ToDo">
<input type="checkbox"
id={this.state.item.id}
name={this.state.item.id}
value={this.state.item.done}/>
<label id={this.state.item.id}>{this.state.item.title}</label>
</div>
)
}
}
export default ToDo;
그런데 현재 상위 컴포넌트가 없는 상태라서 item.id, item.done, item.title을 묶을 수 있는 클래스가 필요하다.
App.js 수정 > ToDo.jsx 파일에 props 전달
import './App.css';
import React from 'react';
import ToDo from './ToDo';
class App extends React.Component {
constructor(props){
super(props)
//3개의 객체를 가진 배열을 생성
//this.state.item = {item:{id:0, "title":"Hello React", "done":true}}
this.state = {item:{id:0, "title":"Hello React", "done":true}}
}
render(){
return(
<div>
{/* Todo에게 item이라는 이름으로 데이터 전달 */}
<ToDo item={this.state.item} />
</div>
)
}
}
export default App;
App.js에 this.state.item이라는 이름으로 데이터 생성
props의 데이터를 ToDo에게 전달
상위 클래스: React.Component 상위 컴포넌트(부모): App 하위 컴포넌트(자식): Todo 하위 클래스: App
배열이나 리스트를 순회하면서 작업을 수행하는 경우
map
데이터를 변환해주는 함수
함수를 대입해서 함수에 데이터를 순서대로 대입해서 리턴한 결과를 모아 다시 배열이나 리스트로 리턴해주는 함수
filter
데이터를 필터링해주는 함수
boolean을 리턴하는 함수를 대입해서 데이터를 순서대로 대입하고 return 값이 true인 데이터만 모아 다시 배열이나 리스트로 리턴해주는 함수
reduce
계산하고 리턴해주는 함수
연산 후 리턴하는 함수를 대입해서 데이터를 순서대로 대입,
return 값을 가지고 다음 함수 호출의 매개변수로 활용해서 결과를 하나의 값으로 리턴해주는 함수
App.js
import './App.css';
import React from 'react';
import ToDo from './ToDo';
// import Sample from './Sample';
class App extends React.Component {
constructor(props){
super(props)
//this.state.time = {item:{id:0, "title":"Hello React", "done":true}}
this.state = {items:[ {id:0, "title":"Hello React", "done":true},
{id:1, "title":"vue", "done":false},
{id:2, "title":"angular", "done":false}]
}
}
render(){
//배열을 순회하면서 출력할 내용을 생성
//item은 배열을 순회할 때 각각의 데이터이고 idx는 인덱스
//배열을 순회하면서 출력물을 만들 때는 key를 설정
//key를 설정하지 않으면 출력에는 문제가 없지만 콘솔에 에러가 출력
let display = this.state.items.map((item, idx) => ( //(아이템, 인덱스)
<ToDo item={item} key={item.id} />
));
return(
<div className="App">
{display}
</div>
)
}
}
export default App;