props
는 부모 컴포넌트가 자식 컴포넌트에 데이터를 전달할 때 사용한다.
props
를 전달받은 자식 컴포넌트에서는 데이터를 수정할 수 없다.
(데이터를 변경하기 위해서는 컴포넌트 내부에서만 사용하는 변수에 값을 넣어 사용해야 한다.)
자식 컴포넌트에서 props에 대한 자료형을 선언해 놓으면, 부모 컴포넌트에서 넘어오는 props 변수들의 자료형과 비교한다. 이때 자료형이 일치하지 않는다면 경고 메시지로 알려주기 때문에 잘못된 데이터를 확인할 수 있다.
리액트 기본 내장 패키지인 propTypes
를 import해 사용하면, 데이터 유효성 검증을 하고 콘솔에 경고 메시지를 출력한다.
import datatype from 'prop-types'
컴포넌트명.propTypes = {
변수명 : datatype.number,
변수명 : datatype.bool,
변수명 : datatype.array,
변수명 : datatype.object,
변수명 : datatype.function,
}
props 값을 Boolean형으로 하위 컴포넌트에 전달할 경우 true나 false 중 하나를 할당한다.
변수를 선언한 후 값을 할당하지 않고 넘기면 true가 기본값으로 할당된다.
props 값을 객체로 하위 컴포넌트에 전달할 경우, 자료형을 object로 선언한다.
import React from 'react';
import PropsObj from './R020_PropsObj'
function App() {
return(
<PropsObj Object Json={{react : '리액트', twohundred: '200'}}/>
)
}
객채 형태(객체 내부 변수들)의 자료형을 선언할 때는 shape
라는 유형을 사용한다.
import React, {Component} from 'react';
import datatype from 'prop-types';
class R020_PropsObj extends Component{
rener() {
let {
Object Json
} = this.props
}
return (
{JSON.stringify(Object Json)}
)
}
R020_PropsObj.proptypes = {
Object Json : datatype.shape({
react: datatype.string,
twohundred: datatype.number,
})
}
props의 자료형을 선언할 때 prop-types
를 사용하는데, 자료형 설정 대신 isRequired
를 조건으로 추가하면 변숫값이 없는 경우 경고 메시지가 발생할 수 있다.
컴포넌트명.propTypes = {
prop명 : datatyep.isRequired,
}
props의 기본값은 부모 컴포넌트에서 값이 넘어 오지 않았을 때 사용한다.
defaultProps
라는 문법을 사용한다.
컴포넌트명.defaultProps = {
prop명 : "기본값" // 숫자, 문자열 등의 기본값 설정
}
props를 하위 컴포넌트 태그 안쪽에 선언해 전달하는 것 이외에도 하위 컴포넌트 태그 사이에 작성된 node를 전달할 수 있다.
node
: html 문서를 구성하는 포괄적인 개념. (ex. 문서 요소, 속성, 텍스트, 주석)App.js
import PropsNode from './PropsNode';
function App(){
return(
<div>
<PropsNode>
<span>node from App.js</span> // node
</PropsNode>
</div>
)
}
export default App;
PropsNode.js
import React, {Component} from 'react';
class PropsNode extends Component{
render(){
return(
<div>
{this.props.children} // 상위 컴포넌트에서 전달한 노드 접근
</div>
)
{
}
props 와 state 의 차이점
props
: 상위 컴포넌트에서 하위 컴포넌트로 데이터를 전달할 때 사용
state
: 하나의 컴포넌트 안에서전역 변수
처럼 사용
this.state.변수명 = value
처럼 state를 직접 변경하면 render() 함수를 호출하지 않으므로 화면에 보이는 state 값은 바뀌기 전 상태로 남게 된다.
따라서 setState()
함수로 state를 변경해야 render() 함수를 호출해 변경된 값을 화면에 보여줄 수 있다.
StateChange = () => {
this.setState({변수명 : value});
}
this.state.변수명 = value
처럼 state를 직접 변경하고 forceUpdate()
함수로 화면을 새로고침하면 render() 함수를 호출해 변경된 값을 화면에 보여줄 수 있다.
StateChange = () => {
this.state.변수명 = value;
this.forceUpdate();
}
class형 컴포넌트에는 Component
와 PureComponent
가 있다.
: 비교 대상이 완전히 동일하지 않으면 변경이 발생했다고 본다.
setState()
함수로 실행한 값은 이전에 있던 state 변숫값과 동일하더라도
Component에서는 새로운 state 변수가 같은 이름으로 생성됐다고 인식한다.
: 비교 대상의 값을 비교해 동일하지 않으면 변경이 발생했다고 본다.
PureComponent
를 import 해서 사용한다.참조 값
은 객체를 생성했을 때 저장되는 메모리 주소로, 완전히 동일한 객체라도 새로 선언하면 다른 참조 값은 갖는다.shallow-equal
패키지는 PureComponent에서 state 값의 변경을 비교하는 것과 동일한 기능을 하는 함수를 제공한다. shallowEqualArrays()
함수를 사용하면 문자열과 배열은 값만 비교하고 객체는 참조 값을 비교한다.
npm install shallow-equal
Component 클래스에서도 shouldComponentUpdate()
와 shallowEqualArrays()
를 사용하면 PureComponent 클래스처럼 값만 비교해 render() 함수를 실행시킬 수 있다.
함수형 컴포넌트 클래스형 컴포넌트와 달리, state가 없고 생명주기 함수를 사용할 수 없다.
import React from 'react';
function 함수명(props){
let { contents } = props;
return (
<h2>{content}</h2>;
)
}
export default 함수명;
함수형 컴포넌트에서 클래스형 컴포넌트와 같이 state와 생명주기 함수와 같은 기능을 사용하기 위해 hook
을 이용한다.
대표적인 hook 함수에는
useState()
,useEffect()
가 있다.
import React, { useState, useEffect } from 'react';
function 함수명(){
const [state, setState] = useState('초기값');
useEffect(() => {
console.log('useEffect');
})
return (
<div>
<h2>{state}</h2>
<button onClick = {() => setState('state 바꾸기')}>버튼</button>
</div>
)
}
export default 함수명;
컴포넌트 단위로 element를 return할 때 하나의 태그로 전체를 감싸지 않으면 에러가 발생한다. 이때 태그로 감싸면 불필요한 태그를 추가하지 않고 사용할 수 있다.
<>
로 사용할 수 있다. 틀린 예시
import React, { useState } from 'react';
function 함수명(){
return(
<p>내용</p>
<span>내용</span>
)
}
export default 함수명;
옳은 예시
import React, { useState } from 'react';
function 함수명(){
return(
<React.Fragment>
<p>내용</p>
<span>내용</span>
</React.Fragment>
)
}
export default 함수명;
import React, { useState } from 'react';
function 함수명(){
return(
<>
<p>내용</p>
<span>내용</span>
<>
)
}
export default 함수명;
반복해서 출력해야 하는 element들을 배열에 넣어두고 map()
함수로 순서대로 나열해 컴포넌트를 return할 수 있다.
import React, { useState } from 'react';
function 함수명(){
const array = [
<li>list1</li>
, <li>list2</li>
. <li>list3</li>
]
return(
<ul>
{array.map(el => el)};
</ul>
)
}
export default 함수명;
bootstrap
은 프론트엔드 디자인을 쉽게 구현할 수 있도록 도와주는 html, css, js 프레임워크다.
bootstrap을 react에서 사용할 수 있도록 패키지로 만든 것이 reactstrap
이다.
reactstrap은 bootstrap css를 포함하고 있지 않기 때문에 bootstrap도 같이 설치해준다.
npm install --save reactstrap
npm install --save bootstrap
알림 영역에 대한 기능을 제공한다.
참고
reactstrap에서 color 속성을 primary, secondary, success, danger, waring, light, dark 중에 선택하면 각각 다른 색을 적용할 수 있다.
App.js
import React from 'react';
import ReactstrapAlerts from '경로';
import 'bootstrap.css'
function App(){
return (
<ReactstrapAlerts/>
)
}
ReactstrapAlerts.js
import React, { useState } from 'react';
import { Alert, UnControlledAlert } from 'reactstrap';
function ReactstrapAlerts(){
return(
<div>
<Alert color="light">
Simple Alert [color : light]
</Alert>
<UnControlledAlert color="warning">
UnControlled Alert [color : warning]
</UnControlledAlert>
</div>
)
}
export default ReactstrapAlerts;
부모 요소에 추가로 특정 문자열이나 숫자를 표시할 때 사용된다.
App.js
import React from 'react';
import ReactstrapBadges from '경로';
import 'bootstrap.css'
function App(){
return (
<ReactstrapBadges/>
)
}
ReactstrapBadges.js
import React, { useState } from 'react';
import { Badge, Button } from 'reactstrap';
function ReactstrapBadges(){
return(
<div>
<h1>Product Name <Badge color="secondary"> hit</Badge></h1>
<Button color="light">
<Badge color="dark"> 4</Badge>
</Button>
</div>
)
}
export default ReactstrapBadges;
페이지 위치 경로를 지정한 웹 네비게이션에 사용된다.
보통 웹사이트 상단에 표시되는 메뉴 리스트에 사용하며 특정 메뉴를 선택하면 해당하는 페이지 위치로 이동시킨다.
App.js
import React from 'react';
import ReactstrapBreadcrumbs from '경로';
import 'bootstrap.css'
function App(){
return (
<ReactstrapBreadcrumbs/>
)
}
ReactstrapBreadcrumbs.js
import React, { useState } from 'react';
import { Breadcrumb, BreadcrumItem } from 'reactstrap';
function ReactstrapBreadcrumbs(){
return(
<div id="top">
<Breadcrumb tag="nav" listTag="div">
<BreadcrumItem tag="a" href="#top">Go top</BreadcrumItem>
<BreadcrumItem tag="a" href="#bottom">Go bottom</BreadcrumItem>
</Breadcrumb>
<div id="bottom">
</div>
</div>
)
}
export default ReactstrapBreadcrumbs;
대표 메뉴를 검색하면 하위 메뉴 리스트가 표시되는 기능
App.js
import React from 'react';
import ReactstrapDropdown from '경로';
import 'bootstrap.css'
function App(){
return (
<ReactstrapDropdown/>
)
}
ReactstrapDropdown.js
import React, { useState } from 'react';
import { ButtonDropdown, DropdownToggle, DropdownMenu, DropdownItem } from 'reactstrap';
function ReactstrapDropdown(){
return(
<ButtonDropdown isOpen={this.state.dropdownOpen} toggle={this.toggle}>
<DropdownToggle caret> 버튼 Dropdown</DropdownToggle>
<DropdownMenu>
<DropdownItem header>헤더</DropdownItem>
<DropdownItem disabled>비활성화 버튼</DropdownItem>
<a href="http://example.com/">
<DropdownItem>example 웹 사이트로 이동</DropdownItem>
</a>
<DropdownItem onClick={e => alert("Alert 버튼")}> Alert 버튼 </DropdownItem>
</DropdownMenu>
</ButtonDropdown>
)
}
export default ReactstrapDropdown;
비슷한 형태와 기능을 하는 버튼들을 그룹으로 관리할 수 있게 지원해준다.
<Button>
태그에 color 속성에 약속된 문자열을 넣으면, 용도에 맞는 버튼 스타일을 지원해준다.
이미지 제목, 부제목, 내용, 버튼 등을 한 세트로 묶는다.
Card 단위로 리스트를 만들어 반복해서 출력하면 정형화된 콘텐츠 목록을 만들 수 있다.
슬라이드를 자동으로 회전시키는 기능을 제공한다.
import React from 'react';
import { UncontrolledCarousel } from 'reactstrap';
const items = [
{
src : 'http://~~',
altText : '슬라이드1 이미지 대체 문구',
caption : '슬라이드1 설명',
header : '슬라이드1 제목',
},
{
src : 'http://~~',
altText : '슬라이드2 이미지 대체 문구',
caption : '슬라이드2 설명',
header : '슬라이드2 제목',
},
{
src : 'http://~~',
altText : '슬라이드3 이미지 대체 문구',
caption : '슬라이드3 설명',
header : '슬라이드3 제목',
}
]
funtion ReactstrapCarousel(){
return(
<UncontrolledCarousel items={items} />
)
}
특정 영역을 펼치고 숨기는 기능을 제공한다.
특정 영역을 서서히 나타내고 숨기는 기능을 제공한다.
기존 <html form>
태그에 깔끔하고 정리된 스타일을 간편하게 사용해 사용할 수 있다.
여러 개의 태그를 하나의 input 그룹으로 묶어 사용할 수 있도록 지원한다.
Jumbotron은 대형 전광판을 의미한다. 넓은 영역에 눈에 띄게 정보를 표시해 사용자의 관심을 불러일으킬 수 있다.
정돈된 스타일의 목록을 표시할 때 사용한다.
Button과 링크에 별도의 태그를 추가하지 않고 속성 값으로 간편하게 사용할 수 있다.
alert()
함수와 마찬가지로 사용자에게 원하는 시점에 알림 창을 띄워 필요한 내용을 보여준다. 웹 브라우저에서 팝업 창을 차단할 수 없고 배경 페이지와 어울리는 디자인을 적용할 수 있다.
웹 사이트의 내부 페이지들로 쉽게 이동할 수 있도록 메뉴 리스트와 링크를 제공한다.
데이터 수가 많아 한 페이지에 모두 표시할 수 없을 때는 여러 페이지에 나눠 표시한다. 페이지 번호, 이전/다음 페이지 첫/마지막 페이지 버튼을 쉽게 구현할 수 있게 지원해준다.
html 요소를 클릭했을 때 요소에 연결된 메시지 박스를 띄울 수 있는 기능을 제공한다.
전체 작업에 대한 현재 진행 상태를 표현해준다.
진행 바 내부에 문자열을 넣을 수 있고, 색상을 적용할 수도 있다.
어떤 작업이 진행되고 있음을 표시하는, 움직이는 원 형태의 디자인을 제공한다.
<html table>
태그에 간편하게 스타일을 적용할 수 있도록 지원해준다.
사용자 동작에 따라 특정 영역에 다른 내용을 표시할 때 사용한다.
sweetalert2는 다양한 디자인과 기능의 알림 창을 지원한다.
기본 자바스크립트 alert()
와 같이 사용자에게 필요한 정보를 알림 창으로 표시한다.
npm install sweetalert2
sweet2는 비동기적으로 동작하기 때문에 동기적으로 사용하기 위해 프로미스의 then 함수를 사용한다.
import React from 'react';
import Swal from 'sweetalert2';
function Sweetalert2Basic(){
Swal.fire('1. SweetAlert').then(result =>
{ alert('2. alert()')} )
}
알림 창의 표시 위치를 결정한다.
실제 삭제 작업을 실행하기 전에 다시 한번 확인하는 알림 창을 표시한다.
웹에서는 클라이언트와 서버가 http 프로토콜
을 통해 요청과 응답을 주고받는다.
http에서 사용하는 방식은 여러 가지가 있지만, GET
과 POST
를 가장 많이 사용한다.
GET
은 데이터를 조회해 가져와 사용하는 것이다.
⭐️ GET 방식은 url? 뒤에
파라미터명=값
형태로 필요한 데이터를 전달한다. 주로 데이터 조회나 검색 등의 기능에 사용된다.
자바스크립트 내장 함수인 fetch를 사용하면 쉽게 비동기 통신을 구현할 수 있다. 비동기 통신
이란, 쉽게 말해 먼저 시작한 작업의 완료 여부와 상관없이 다음 작업을 실행하는 것이다.
이때 fetch 함수의 비동기적 특징 때문에 아래 line 1
에서 데이터를 가져오기 전에 line 2
가 실행돼 에러가 발생할 수 있다.
이런 에러는 비동기 함수에 동기적인 기능을 추가해 해결할 수 있다. 이때 사용하는 것이 async
와 await
문법이다. 비동기 함수를 실행하는 함수에 async를 추가하고 동기적으로 처리돼야 하는 함수 구문 앞에 await를 추가한다.
import React, { useState, useCallback, useEffect } from 'react';
function fetchGet(){
const [data, setData] = useState([]);
const fetchHandler = useCallback(async () => {
const response = await fetch('http://date.jsontest.com/'); // line 1
const body = await response.json(); // line 2
setData(body);
}, [])
useEffect(FetchHandler,[FetchHandler]);
return (
<h1>fetch get</h1>
)
}
export default fetchGet;
useCallback
콜백 함수의 최적화를 위해
useCallback
을 사용한다.
useCallback은 해당 함수가 동일한 입력값을 받았을 때 이전에 계산한 결과를 재사용한다. 이를 통해, 같은 함수를 반복적으로 재생성하지 않고 기존의 함수를 재사용하므로서, 불필요한 렌더링을 줄일 수 있다.useEffect
fetch 작업을 수행하는 코드를 useEffect 내에 작성하면, 컴포넌트가 렌더링되고 난 후에(fetch 작업이 끝나고 나서) 데이터를 가져와서 화면에 렌더링할 수 있다. 또한, useEffect를 사용하면 데이터를 가져오는 중에도 사용자 인터페이스가 멈추거나 끊김 없이 계속 작동할 수 있도록 보장할 수 있다.
POST는 서버의 상태나 데이터를 변경하는 등의 수행 작업에 사용된다.
url 뒤에 파라미터를 표시하지 않고 사용할 수 있다는 장점이 있다.
fetch 방법은 get과 비슷하지만, 두 번째 파라미터에 post 호출에 대한 정보가 추가된다.
import React, { useState, useEffect } from 'react';
function fetchPost(){
const [data, setData] = useState([]);
const fetchHandler = async () => {
const response = await fetch('http://date.jsontest.com/', {
method : 'POST', // post 방식으로 통신을 하겠다는 의미
headers : {
'Content-Type' : 'application/json',
// 어떤 형태의 데이터를 사용할지 지정한다.
// json 형태의 데이터를 사용하기 위해 application/json을 할당한다.
},
body : JSON.stringify(data),
});
}
useEffect(FetchHandler,[FetchHandler]);
return (
<h1>fetch post</h1>
)
}
export default fetchPost;
axios도 fetch와 마찬가지로 비동기 통신
을 지원한다.
axios는 fetch와 달리, 별도로 설치한 후 import해 사용해야 한다.
npm install -save axios
⭐️ fetch와 axios의 차이점
fetch와 axios는 둘 다 JavaScript에서 HTTP 요청을 보내는 데 사용되는 라이브러리이다.
가장 큰 차이점 중 하나는 fetch가내장된 브라우저 API
이고, axios가브라우저 및 Node.js
에서 사용할 수 있는JavaScript 라이브러리
라는 것이다. 따라서 fetch는 브라우저에서 기본적으로 사용 가능하지만, Node.js에서는 추가 작업이 필요하다.
또한 axios는 fetch보다 강력한 기능을 제공한다. 예를 들어, axios는 HTTP 요청 및 응답을 자동으로 JSON으로 변환하고, 요청 취소 및 인터셉터 등과 같은 기능을 제공한다. 이러한 기능들은 fetch로 구현하기가 어렵거나 불가능하다.
하지만, fetch는 브라우저 API이므로 브라우저의 기능과 함께 사용될 때 일관성 있는 브라우저 경험을 제공할 수 있다.
import React from 'react';
import axios from 'axios'; // import 해오기
function AxiosGet(){
axios.get('http://date.jsontest.com/')
.then( response => alert(response.data.date))
return(
<h1>axios get</h1>
)
}
export default AxiosGet;
get 방식과 거의 동일하지만, post 함수의 파라미터로 json과 같은 형태의 데이터를 넣고 http body에 담아 url을 호출할 수 있다는 차이점이 있다.
json 데이터는 {key: value}
형태로 사용한다.
import React from 'react';
import axios from 'axios'; // import 해오기
function AxiosPost(){
axios.post('http://date.jsontest.com/',{
a : "react", b : 200
})
.then( response => alert(response.data.date))
return(
<h1>axios post</h1>
)
}
export default AxiosPost;
자바스크립트는 비동기적
으로 동작하기 때문에 먼저 실행된 작업이 끝나지 않았더라도 다음 작업이 시작될 수 있다.
대표적인 것이
setTimeout()
함수이다.
setTimeout()
함수는 JavaScript에서 비동기적인 타이머를 설정할 때 사용하는 함수이다. 이 함수는 일정 시간이 지난 후에 지정된 콜백 함수를 호출한다.1번 코드 2번 코드(setTimeout으로 2초 후 실행되도록 했을 때) 3번 코드
1번 -> 2번(2초 기다리고) -> 3번 순서대로(동기적으로) 실행되지 않고, 1번 -> 3번 -> 2번 순서대로(비동기적으로) 실행된다. 이를 동기적으로 실행시키고 싶을 때 콜백 함수를 사용해주면 된다.
function CallbackFunc(){
console.log("1번 코드");
setTimeout(function(){
console.log("2번 코드")
}, 2000);
console.log("3번 코드");
}
CallbackFunc();
// 실행 결과 : 1번 코드 -> 3번 코드 -> 2번 코드
콜백 함수
를 이용하면 특정 코드에 순서를 정해 원하는 시점에 실행할 수 있다.
콜백 함수란 다른 함수의 인자로써 이용되는 함수로, 어떤 이벤트에 의해 호출되는 함수를 말한다.
위의 코드의 경우 빨간 부분이 콜백 함수에 해당한다.
setTimeout(function(){
console.log("2번 코드")
}, 2000);
만약 1번 코드 -> 2번 코드 -> 3번 코드의 순서로 실행을 시키고 싶을 경우, 2번 코드의 콜백 함수 내부에서 다시 콜백 함수를 이용해 3번 코드를 호출하면 된다.
function CallbackFunc() {
console.log("1번 코드");
setTimeout(function() {
console.log("2번 코드");
setTimeout(function() {
console.log("3번 코드");
}, 1000);
}, 2000);
}
CallbackFunc();
// 실행 결과 : 1번 코드 -> 2번 코드 -> 3번 코드
그러나 콜백 함수가 증가할수록 함수 안에 또 다른 함수를 계속 추가해야 한다. 이런 형태를 콜백 지옥
이라고 한다. 콜백 함수를 여러 번 사용할수록 코드가 더 지저분해진다는 단점이 있다.
-> 이를 개선하기 위해 나온 것이 promise & then
과 async & await
이다.
promise는 콜백 함수와 같이 비동기적으로 동작하는 코드를 동기적으로 구현할 때 사용한다. 콜백 함수와 달리 코드 가독성
을 높일 수 있고 예외 처리
도 쉽게 할 수 있다.
위의 예제를 promise와 then을 이용해 해결하면 다음과 같다.
function CallbackFunc() {
console.log("1번 코드");
new Promise((resolve) => setTimeout(resolve, 2000))
.then(() => {
console.log("2번 코드");
})
.then(() => {
console.log("3번 코드");
})
}
CallbackFunc();
Promise의 상태가 대기, 이행, 거부 중 거부 상태가 됐을 때 catch 함수를 실행한다. 대기 상태의 Promise에 에러가 발생해 이행으로 상태 변화를 하지 못하는 경우다.
function CallbackFunc() {
new Promise((resolve, reject) => {
reject(Error("Error Info")) // reject 상태
})
.then(result => console.log("then " + result)) // 실행안됨
.catch(result => console.log("catch " + result)) // catch Error: Error Info 출력.
}
CallbackFunc();