React 공부(1)

Lee.GS·2021년 3월 1일
0

React에 대한 기본적인 내용은 Velopert님의 리액트를 다루는 기술 책을 토대로 공부하였습니다.

React를 왜 사용하는가?

  • MVC (Model-View-ontroller) 아키텍쳐, MVVM (Model-View-View Model) 아키텍쳐, MVW (Model-View-Whatever)아키텍쳐와 같은 모델과 뷰가 공통점으로 있는 다른 프레임워크에 비해 오직 View만 신경쓰는 라이브러리이다.
    기존의 뷰를 날려버리고 처음부터 새로 렌더링하는 방식으로 성능을 최적화한다.

React의 특징

1. Virtual DOM

  • DOM이란 Document Object Model으로, 객체로 문서구조를 표현하며 XML이나 HTML로 작성한다.
  • 데이터를 업데이트하면 전체 UI를 Virutal DOM에 리렌더링하여 이전 Virtual DOM에 있던 내용과 현재 내용을 비교하여 바뀐 부분만 실제 DOM에 적용한다.

2. 기타 특징

  • 웹 프레임워크가 MVC 또는 MVW 등의 구조를 지향하는 것과 달리 React는 오직 뷰만 담당하며, React는 프레임워크가 아니라 라이브러리이므로 프레임워크와 달리 Ajax, 라우팅과 같은 기능은 직접 구현하여 사용하여야 한다.
    Ex) 라우팅 - React-Router, Ajax - axios / fetch, 상태관리 - Redux / MobX
  • 리액트는 다른 웹 프레임워크나 라이브러리와 혼용할 수 있다.
  • React + AngularJS / Backbone.js / Meteor 등등

3. JSX

  • 자바스크립트와 HTML을 한번에 합쳐놓은 것 같은 문법
  • JSX로 작성한 코드는 브라우저에서 실행되기 전에 바벨을 통해 번들링되는 과정에서 일반 JS 코드로 변환됨.
Function App(){
	Return (
		<div>
			Hello <b>React</b>
		</div>
	);
}
Function App() {
	Return React.createElement(“div”, null, “Hello”, React.createElement(“b”, null, “react”));
}

위의 두 코드의 결과는 같다.

JSX는 우리가 알고 있는 div와 span과 같은 HTML태그 뿐 아니라 컴포넌트 또한
HTML태그 쓰듯이 작성을 한다.
Ex) ReactDOM.render(, document.getElementByld(‘root’));

JSX 문법

  • JSX는 편리한 문법이지만, 올바르게 사용하려면 몇가지 규칙을 준수해야 한다.

1. 컴포넌트에 여러 요소가 있다면 반드시 부모 요소 하나로 감싸야 한다.

  • Why?
    Virutal DOM에서 컴포넌트 변화를 감지할 때, 효율적으로 비교할 수 있도록 컴포넌트 내부는 하나의 DOM 트리구조로 이루어져야 한다는 규칙이 있기 때문이다.

EX)

return (
	<h1>리액트 안녕</h1>
	<h2>잘 작동하나?</h2>
)

위의 코드는 요소 여러 개가 부모 요소 하나에 의하여 감싸져 있지 않기 때문에 오류가 난다.
이를 해결하려면 아래의 코드와 같이 작성하여 해결할 수 있다.

Return (
	<div>
		<h1>리액트 안녕</h1>
		<h2>잘 작동하니?</h2>
	</div>
) 

2. 자바스크립트 표현

  • JSX 안에서 코드를 { } 로 감싸면 자바스크립트 표현식을 사용할 수 있다.
    EX)
Function App() {
Const name = ‘리액트’;
Return (
	<h1>{name} 안녕!</h1>
	);
}

3. if문 대신 조건부 연산자( 삼항 연산자 )

  • JSX 내부에서는 if문을 사용할 수 없습니다.
  • 조건에 따른 내용을 렌더링 할 때는 JSX밖에서 if문을 사용하여 값을 설정하거나, { } 안에 조건부연산자를 사용하면 됩니다.
    EX)
Return (
	<div>
		{name === ‘리액트’ ? (
			<h1>리액트입니다.</h1>
		) : (
			<h2>리액트가 아닙니다.</h2>
		)}
	</div>
);

4. AND 연산자를 사용한 조건부 렌더링

  • 개발하다 보면 특정조건을 만족할 때 내용을 보여주고, 만족하지 않을 경우 아예 렌더링하지 않아야 하는 경우
    EX)
Function App() {
	Const name = ‘리액트’;
	Return <div>{name === ‘리액트’ && <h1> 리액트입니다.</h1>}<.div>;
}

위와 같이 코드를 작성하면 name이 ‘리액트’일 떄는 '리액트입니다'가 렌더링되고 아닐 경우 아무것도 나타나지 않음.

5. 인라인 스타일링

  • DOM 요소에 스타일을 적용할 때는 문자열 형태로 넣는 것이 아니라 객체 형태로 넣어주어야 한다.
    ex )
render() {
	const tempStyle={
		display:"inline-block",
		width:"100px",
		height:"100px",
		boder:"1px solid black",
		background:"orange",
	}
	return (
		<Fragment>
		<div style={tempStyle}></div>
		</Fragment>
	);
	}
}
  • background-color와 같이 - 문자가 포함될 경우 카멜 표기법인 backgroundColor로 작성해야 한다.

6. class 대신 className 사용

  • Why className ?
    html에서는 ‘.’을 이용하여 class에 대한 css를 적용하지만, 리액트에서는 class가 예약어라 사용이 불가능하다.
    그래서 className을 이용해서 css를 적용한다.
    Ex )
<div className = “react” >{name} </div>

컴포넌트(Component)

  • 컴포넌트를 선언하는 방식은 함수형, 클래스형 2가지가 있으며 각각 차이가 있다.

(1) 함수형 컴포넌트 선언

Function App() {
	Const name = ‘리액트’
	Return <div className = “react’>{name}</div>;
}

----- 기본 함수표기법 ( ↑ )과 Arrow 함수 표기법( ↓ ) ----------

const App = () => {
	const name = ‘리액트’
	return <div className = “react”>{name}</div>;
}

(2) 클래스형 컴포넌트 선언

Class App extends Component {
	Render() {
		Const name = ‘리액트’;
		Return <div className = “react”>[name}</div>;
	}
}

클래스형 컴포넌트와 함수형 컴포넌트의 차이

  • 클래스형 컴포넌트와 함수형 컴포넌트의 차이는 클래스형 컴포넌트의 경우 state기능 및 라이프사이클 기능을 사용할 수 있으며, 임의 메서드를 정의할 수 있습니다.
  • 클래스형 컴포넌트는 render함수가 꼭 있어야 하며, 그 안에서 JSX를 반환해야 합니다
  • 함수형 컴포넌트의 장점은 선언하기 편하며 메모리자원도 클래스형 컴포넌트보다 덜 사용합니다.
  • 단점은 state와 라이프사이클 API의 사용이 불가능하다는 점인데 이러한 단점은 Hooks라는 기능을 통해 해결.
  • 공식 매뉴얼에는 함수형 컴포넌트 + Hooks 사용을 권장하지만, 클래스형 컴포넌트의 기능도 꼭 알아야 한다.
    ※ VS CODE에서 Reactjs Code Snippet 확장 프로그램을 통해 에디터에서 rsc / rcc 를 입력하고 Enter를 누르면 함수형 컴포넌트 / 클래스형 컴포넌트를 간편하게 생성할 수 있다.

모듈 내보내기(export) 및 불러오기(import)

1. 모듈 내보내기

Export default MyComponent; <- MyComponent라는 컴포넌트를 모듈로 내보내는 역할

2. 모듈 불러오기

Import MyComponent from ‘./MyComponent’; <- MyComponent라는 컴포넌트를 불러오는 역할

프롭스(Props)

  • properties를 줄인 표현으로 컴포넌트 속성을 설정할 때 사용하며 부모 컴포넌트에서 설정한다.

1. JSX 내부에서 렌더링

Const MyComponent = props => {
	Return <div>안녕하세요, 제 이름은 {props.name}입니다.</div>;
};

2. 컴포넌트를 사용할 때 props값 지정하기

Const App = () => {
	Return <MyComponent name=“React” />;
};

3. props 기본값 설정 : defaultProps

Const MyComponent = props => {
	Return <div>안녕하세요, 제 이름은 {props.name}입니다.</div>;
};

MyComponent.defaultProps = {
	Name : ‘기본 이름’
};

4. 비구조화 할당 문법을 통해 props 내부 값 추출하기

(1) 함수형 컴포넌트
Const Parent  = props => {
	Const { name, children } = props;
	Return (
	<div>
		안녕하세요, 제 이름은 {name} 입니다. <br />
		Children 값은 {children}입니다.
	</div>
	)
};
Const Child = ({ name, children }) => {
	Return (
	<div>
		안녕하세요, 제 이름은 {name} 입니다. <br />
		Children 값은 {children}입니다.
	</div>
	)
};

(2) 클래스형 컴포넌트

Class MyComponent extends Component {
	Render() {
		Const { name, children } = this.props; // 비구조화 할당
		Return (
			<div>
				안녕하세요, 제 이름은 {name} 입니다. <br />
				Children 값은 {children}입니다.
			</div>
		);
	}
}

State(상태 유지)

(1)함수형 컴포넌트

useState 함수로 배열을 반환하며, 첫 번째 원소는 현재, 두 번째 원소는 상태를 바꾸어 준다.

function App() {
	const [count, setCount] = useState( 0 ); // useState(0)은 초기값을 0으로 설정한다.
	
	return(
	<div>
		<p>현재 클릭된 횟수는 {count}입니다.</p>
		<button onClick={() => setCount( count + 1)}>Click Count +1</button>
	</div>
}
// state로 설정되어 있는 count를 onClick을 통해 button클릭시 count가 1씩 증가하도록 해줌.

(2)클래스형 컴포넌트

state의 형식은 객체이며, this.setState 함수로 state값을 변경할 수 있다.

class App extends Component {
	state = {
		count : 50
	};
	countPlus = () => {
		this.setState({
			count : this.state.count + 1
		});
};
render() {
	return (
		<div>
			<p>현재 클릭된 횟수는 {this.state.count} 입니다.</p>
			<button onClick={this.countPlus}>Click Count +1</button>
         )
}

이벤트 핸들링

(1) 함수형 컴포넌트에서의 이벤트 핸들링

  • const + 함수 형태로 선언해야 한다.
  • 요소에서 적응하기 위해 this를 적용할 필요가 없다.
    ex)
const ClickClick = ()=> {
	alert(message)
	setMassage(‘’);
}
<button onClick={ClickClick}>이벤트핸들링</button>

(2)클래스형 컴포넌트에서의 이벤트 핸들링

  • 함수 선언시 애로우 함수로 바로 선언할 수 있다.
  • 요소에서 적용하기 위해서는 this가 필요하다
    ex)
ClickClick = () => {
	alert(this.state.message)
	this.setState({
		message : ‘ ’
	});
}
<button onClick={this.ClickClick}>이벤트핸들링</button>

왜 App.js에 있는 화면이 메인으로 띄워질까?

리액트는 번들러를 활용합니다. 특히 리액트 프로젝트에서는 webpack을 주로 사용하는데,
node_modules에 가 보면 webpack이 알아서 설치되어 있음을 확인하실 수 있습니다.
webpack은 가장 처음으로 읽어들이는 entry point부터 시작하여 필요한 모든 모듈을 다 불러온 뒤 번들링하여 한 파일로 합쳐서 bundle.js 에 저장하는 역할을 합니다.
이 때 webpack 설정파일에 가 보면 entry point가 index.js로 정의되어 있을 것입니다.
그러면 index.js 에 가 보겠습니다.

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

이처럼 webpack의 entry point였던 index.js에, App.js의 요소를 그리도록 작성되어 있기 때문에, 첫 화면에 App.js의 것들이 보여지게 되었던 것입니다.

React에서의 REST API 사용하기

  • 일반적인 javascript에서 API를 연동하기 위해서는 보통 fetch-API를 사용한다. React 또한 Fetch-api를 사용할 수 있는데 React에서는 axios 사용하는 것을 더욱 선호한다.

fetch-API와 axios의 차이 출처

fetch-Api 와 axios의 차이

Fetch


const url = 'http://localhost/test.htm';
const options = {
  method: 'POST',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json;charset=UTF-8'
  },
  body: JSON.stringify({
    a: 10,
    b: 20
  })
};

fetch(url, options)
  .then(response => {
    console.log(response.status);
  });

axios

const options = {
  url: 'http://localhost/test.htm',
  method: 'POST',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json;charset=UTF-8'
  },
  data: {
    a: 10,
    b: 20
  }
};

axios(options)
  .then(response => {
    console.log(response.status);
  });

위의 fetch와 axios코드 둘다 같은 기능을 수행하는 코드이다.
코드에서의 차이점을 보면

  • fetch의 body 부분은 stringify() 되어진다.
  • fetch에서는 URL이 fetch()함수의 인자로 들어가지만, axios에서는 URL이 option 객체로 들어간다.
    코드 외적으로는
  • axios는 모든 브라우저와 호환이 가능하지만 fetch는 한정된 브라우저에서만 가능하다
  • Response TimeOut은 axios는 간단하지만 fetch는 복잡하다.
  • Automatic JSON Data transform이 axios는 가능하지만 fetch는 불가능하다.

결론
Axios는 대부분 HTTP 통신의 요구사항을 컴팩트한 패키지로써 사용하기 쉽게 설계되었다.
브라우저에서 제공하는 fetch()메서드를 이용해서 axios를 완벽히 재현할 수 있지만, 편하게 axios를 사용하자.

axios의 장점

  • 오래된 브라우저에서도 지원한다. - 요청을 중단할 수 있다 - response timeout을 쉽게 지정할 수 있다.
  • CSRF 보호 기능이 내장되어있다. - upload progress를 지원한다. - JSON을 자동으로 변환해준다.

axios를 사용하지 않을 경우와 사용했을 경우의 차이

// axios를 사용하지 않을 경우 ( GET )

let xhr = new XMLHttpRequest();
xhr.open('GET', 'url', true);
xhr.setRequestHeader('Content-type', 'application/json');
xhr.onreadystatechange = () => {
  if (xhr.readyState === 4 && xhr.status === 200) {
      (perform some code);
  } else {
    (handle error)
  }
};
xhr.send();

axios를 사용하지 않는다고 가정하면 우리는 XMLHttpRequest()를 사용해서 open과 onreadystatechange등을 사용해서 복잡한 작업들을 해줘야 한다. onreadystatechange는 무엇이고, asyncronose하게 작업을 할 때는 또 다른 고민들을 해야한다.

// axios를 사용할 경우 ( GET )

axios.get('url')
  .then((response) => {
    console.log(response);
  })
  .catch((response) => {
    console.log(error);
  });

마법처럼 아주 간단히 사용할 수 있다.

// axios를 사용하지 않을 경우 ( POST )

let xhr = new XMLHttpRequest();

xhr.open('POST', 'url', true);

xhr.setRequestHeader('Content-type', 'application/json');
xhr.setRequestHeader('Accept', 'application/json');
xhr.onreadystatechange = () => {
  if (xhr.readyState === 4 && xhr.status === 200) {
    console.log(xhr.response);
  } else {
    (handle error)
  }
};
xhr.send();

// axios를 사용할 경우 ( POST )

axios.post( 'url',
  {
    contact: 'James',
    email: 'james.h@gmail.com'
  },
  {
    headers:{
      'Content-type': 'application/json',
      'Accept': 'application/json'
    }
  }
)
  .then((response) => {
    console.log(response.data);
  })
  .catch((response) => {
    console.log('Error!)
  });

POST의 경우 GET보다는 코드가 길어졌지만, axios를 사용하지 않은 코드와 비교하면 훨씬 간단하다.

axios 사용법

  • npm install axios
  • yarn add axios

Rest Api axios에서 사용하기 출처

Rest API를 axios에서 사용하는 방법

  • REST API에는 대표적으로 다음과 같은 메서드가 있다.
    1. GET : 데이터 조회
    2. POST : 데이터 등록 및 전송
    3. PUT : 데이터 수정
    4. DELETE : 데이터 삭제

axios 사용하기

  • axios의 Request method에는 다음과 같은 것들이 있다.
    GET : axios.get(url[, config]) - GET를 통해 해당 리소스를 조회합니다. 리소스를 조회하고 해당 도큐먼트에 대한 자세한 정보를 가져온다.
    POST : axios.post(url, data[, config]) - 해당 URI를 요청하면 리소스를 생성합니다.
    PUT : axios.put(url, data[, config]) - PUT를 통해 해당 리소스를 수정합니다.
    DELETE : axios.delete(url[, config]) - DELETE를 통해 리소스를 삭제합니다.

axios에서 Request Method를 사용하기 위해서는 axios에 .을 붙히며 소문자로 Req Method를 넣어주면 된다.
그리고 해당 메서드의 파라미터에는 API의 주소를 넣는다.
일반적으로 우리는 axios의 4가지 기본 메서드를 사용하기 위해 지정해야할 것들이 있다.
기본적으로 4가지 Params를 axios에 알려줘야 한다.
1. Method
2. Url
3. Data (optional)
4. Params (optional)

axios({
    method: "get",
    url: "url",
    responseType: "type"
}).then(function (response) {
    // response Action
});

위와 같이 사용하는 것이 가장 기본적인 axios에 대한 사용법이다.
만약 POST 메서드에서 data를 전송하기 위해서는 url 밑에 data Object를 추가하면 된다.

단축된 axios 메서드

  1. axios.get()
  • get 메서드를 단축된 속성으로 사용하려면 get 메서드를 사용하면 된다.
  • get 메서드에는 2가지 상황이 크게 존재하며 2가지 상황에 따라 params: {} 객체가 존재할지 안할지가 결정된다.
    (1) 단순 데이터(페이지 요청, 지정된 요청) 요청을 수행할 경우
    (2) 파라미터 데이터를 포함시키는 경우 (사용자 번호에 따른 조회)
// 단순 데이터를 요청할 경우
axios.get("url")
    .then(function (response) {
         // response  
    }).catch(function (error) {
        // 오류발생시 실행
    }).then(function() {
        // 항상 실행
    });

// 파라미터 데이터를 포함시키는 경우
axios.get("url", {
      params: {
        id: 123
      }
    })
    .then(function (response) {
         // response  
    }).catch(function (error) {
        // 오류발생시 실행
    }).then(function() {
        // 항상 실행
    });
  1. axios.post()
  • post 메서드에는 일반적으로 데이터를 Message Body에 포함시켜 보낸다.
  • 위에서 봤던 get 메서드에서 params를 사용한 경우와 비슷하게 수행된다.
axios.post("url", {
        username: "",
        password: ""
    })
    .then(function (response) {
         // response  
    }).catch(function (error) {
        // 오류발생시 실행
    }).then(function() {
        // 항상 실행
    });
  1. axios.put()
  • put 메서드는 서버 내부적으로 get -> post 과정을 거치기 때문에 post 메서드와 비슷한 형태이다.
axios.put("url", {
        username: "",
        password: ""
    })
    .then(function (response) {
         // response  
    }).catch(function (error) {
        // 오류발생시 실행
    }).then(function() {
        // 항상 실행
    });
  1. axios.delete()
  • delete 메서드에는 일반적으로 body가 비어있다. 그래서 형태는 get과 비슷한 형태를 띄지만 한 번 delete 메서드가 서버에 들어가게 된다면 서버 내에서 삭제 process를 진행하게 된다.
// 일반적인 delete
axios.delete('/user?ID=12345')
  .then(function (response) {
    // handle success
    console.log(response);
  })
  .catch(function (error) {
    // handle error
    console.log(error);
  })
  .then(function () {
    // always executed
  });

/* 
많은 데이터를 요청할 경우 query나 params가 많아져서 헤더에 많은 정보를 담을 수 없을 때는 두 번째 인자에 data를 추가해줄 수 있다.
*/

axios.delete('/user?ID=12345',{
    data: {
      post_id: 1,
      comment_id: 13,
      username: "foo"
    }
  })
  .then(function (response) {
    // handle success
    console.log(response);
  })
  .catch(function (error) {
    // handle error
    console.log(error);
  })
  .then(function () {
    // always executed
  });

0개의 댓글