프로젝트를 진행하면서 useState를 통해 한개의 데이터만을 관리하기도 했지만 여러개의 데이터가 들어가있는 객체 또는 배열을 관리해야 했다.
예를들어 페이징 기능을 수행하기 위해 pageNum을 관리한다고 하면 간단하게 setPageNum(2) 이런 식으로 처리하고 관리하기 쉬웠으나 객체 또는 배열을 관리하는건 다르게 처리해야 했기에 정리.
//pageNum. 단일 데이터 초기값을 1로 설정const [pageNum, setPageNum] = useState(1);
//게시글 input 값 관리//title, content를 담고 있는 객체 구조. 초기값은 둘다 '' 로 설정const [values, setValues] = useState({
title: '',
content: '',
});
//게시글 리스트 값 관리//페이지 접근 시 리스트를 담아 처리.//기본값으로 [] 빈 배열로 설정.const [boardData, setBoardData] = usetState([]);
//단일 데이터 set
setPageNum(2);
//객체 데이터 set
setValues({
title: 'setTitle',
content: 'setContent',
});
//객체 데이터 중 하나의 데이터만 set
setValues({
...values,
title: 'setTitle2',
});
//위 하나의 객체 데이터를 수정하는 set 활용//onChange가 발생할 때 state를 set
setValues({
...values,
[e.target.name]: e.target.value,
});
//리스트 데이터 set
setBoardData(response.data.content);
//배열 데이터 setconst boardArray = [];
boardArray.push({data: data1, ...});
boardArray.push({data: data2, ...});
//...
setBoardData(boardArray);
//boardData에 객체를 추가하는 경우const boardArray = [...boardData];
boardArray.push({data: data10, ...});
//...
setBoardData(boardArray);
프로젝트를 진행하면서 useState는 이렇게 사용했다.
가장 간단한 단일 데이터는 React를 학습하면서 배운 useState 사용법 그대로 사용.
객체까지도 학습한 내용만으로 해결이 가능했다.
객체의 경우 단순하게 모든 데이터를 직접 작성해 set을 해주는 방법이 있고, 그 객체 안에서 하나의 값만 수정하고자 한다면 다르게 처리해야 했다.
위 코드처럼 title, content 중 title 하나만 값을 변경하고자 한다면 content의 값은 유지되어야 한다.
이때 사용할 수 있는 방법이 전개 연산자(Spread Operator)를 사용하는 것이다.
전개연산자는 ES6 문법으로 배열 또는 객체를 넘기는 용도로 사용된다.
...values의 의미는 기존에 values에 담겨있는 값을 그대로 담아준다고 볼 수 있다.
그럼 위 코드에서 ...values를 통해 title: 'setTitle1', content: 'setContent1'이 담기게 될 것이고 그 이후 title을 setTitle2로 바꾸게 되면서 set 되는 데이터는 title: 'setTitle2', content: 'setContent2' 가 된다.
이걸 input에서 onChange 핸들링으로 처리하도록 하는 것으로 입력이 끝난 후 submit이 발생했을 때 values값을 확인하는 것으로 input 들의 값을 알아낼 수 있다.
...values로 다른 input 데이터는 다시 담아 유지할 수 있도록 하고 e.target.name 과 e.target.value로 input에 작성해둔 name값, 작성한 value 값을 가져와 set 해주게 된다.
그럼 입력창의 value를 좀 더 수월하게 관리할 수 있게 된다.
그리고 마지막 배열.
axios 요청에 대한 응답으로 리스트 데이터를 받는 경우 간단하게 res.data를 set 해주는 것으로 배열형태로 담을 수 있다.
문제는 배열을 직접 제어해야 하는 경우다.
배열을 직접 제어하는 것이 가장 처음 렌더링 될때만 수행하게 되는 경우도 있지만 매번 직접 제어해야 하는 경우도 있다.
예를들어 이미지 파일 업로드에서 업로드할 파일과 중간에 사용자가 삭제 버튼을 눌러 사진을 제거했을때의 경우가 있다.
사용자가 파일 5개를 업로드 하고자 선택을 하면 가장 먼저 배열에 파일들을 담아 setImageData 같이 처리하게 될 것이다.
근데 3번째 파일을 지우려고 삭제 버튼을 눌렀다면?
set 된 데이터들 중 3번째 파일 데이터를 삭제하고 나머지 데이터만 남겨야 한다.
하지만 useState는 readOnly로 수행된다.
그래서 imageData 라는 state에서 특정 데이터를 삭제하고 나머지를 set 해주기 위해서는 배열을 사용해야 했다.
이때 처리한 방법이 가장 마지막 코드와 같은 방법이다.
삭제 버튼의 onClick이 발생했을 때 handleOnClick에서는 비어있는 새로운 배열에 전개 연산자로 state 값을 그대로 담아준다.
그리고 3번째 파일이니 2번 인덱스에 대한 값을 찾는다.
그리고 그 파일을 배열에서 제거한 뒤 setState를 통해 set을 해주게 되면 사용자의 요청대로 특정 위치의 데이터만 삭제할 수 있게 된다.
마지막으로 useState를 사용하며 주의해야 할 점.
React 학습에서는 보통 초기값을 설정하지 않고 처리하는 경우가 많았다.
그리고 초기값을 잘못 설정하는 경우 재 렌더링 될때마다 의도하지 않은 값이 설정될 수 있기 때문에 잘 고민해서 초기값 설정을 해야 한다고도 들었다.
프로젝트를 진행하면서 문제가 발생한 부분들은 대부분 초기값에 대한 문제가 많았다.
대부분의 컴포넌트에서 서버에 데이터를 요청한 뒤 setData 에 담아주도록 하고 있는데 이 axios 요청은 useEffect에서 보내도록 해두었다.
거의 첫 렌더링에서만 수행하면 되는 요청이기 때문이라는 생각이었기 때문에 useEffect를 사용해 호출하도록 했는데 문제는 useEffect는 렌더링 후에 수행된다는 점이었다.
해당 컴포넌트가 하위 컴포넌트를 갖지 않고 처리한다면, 또는 해당 값이 null이라도 렌더링에서 오류가 발생하지 않는다면 초기값은 이상하게 설정하지만 않으면 문제가 되지 않았다.
하지만 리스트와 같이 하위 컴포넌트를 두고 그 하위 컴포넌트를 map을 통해 반복 하도록 했다면 얘기가 다르다.
반복문을 통해 처리하라고 했으면 '얘는 배열 타입이야' 라고 알려줘야 한다.
근데 state의 초기값을 아무것도 설정하지 않고 얘로 반복문 돌려서 처리해줘 라고 하면 오류가 발생하는 것.
'단일 객체를 반복문을 왜 돌림?' 이런 느낌이다..
그래서 state의 초기값을 [] 로 빈 배열로 초기화를 해둬야 한다.
혹은 배열이 아니더라도 하위 컴포넌트에서 해당 state 값으로 무언가를 처리하는데 오류가 발생할 여지가 있다면 초기값을 설정해 오류가 발생하지 않도록 해야 한다.
배열 state 코드가 게시글 리스트 코드를 예로 들었으니 게시글 리스트를 예로 들어본다.
리스트 페이지 접근 -> 렌더링 -> useEffect 수행 -> axios 요청, 응답 후 setData -> state가 변경되었으니 재렌더링.
이 순서로 발생하기 때문에 1차 렌더링 시에 오류가 발생해 useEffect가 제대로 수행되지 않거나 수행되더라도 재 렌더링이 수행되지 않게 된다.
동기방식은 서버에 신호를 보냈을 때 응답이 돌아와야 다음 동작을 수행할 수 있고 비동기 방식은 그와 반대로
신호를 보냈을때 응답 상태와 상관없이 다음 동작을 수행할 수 있다는 점이 다르다.
Ajax를 이용하는 이유는 화면 전환 없이 클라이언트와 서버간에XML, JSON(JavaScript Object Notation), 텍스트,
HTML등의 정보를 교환하기 위해서이다.
다시말해, Ajax를 이용하면 사용자가 서버에 자료를 요청할 때 화면전환없이 요청한 자료를 전송받을 수 있다.
또한 자료를 요청할 경우 어느정도 시간이 소요되는데 반해 Ajax를 이용하면 사용자가 기다릴 필요 없이
다른 작업을 바로 수행할 수 있다.
Ajax 관련 메소드
종류
설명
load()
외부 컨텐츠를 가져올 때 사용한다.
$.ajax()
데이터를 서버에 HTTP POST, GET 방식으로 전송할 수 있으며, HTML, XML, JSON, 텍스트 유형에 데이터를 요청할 수 있는 통합적인 메소드이다. 이 표에 있는 $.post(), $.get(), $.getJSON() 메소드의 기능을 하나로 합쳐 놓은것이라고 보면 된다.
$.post()
데이터를 서버에 HTTP POST 방식으로 전송한 후 서버측의 응답을 받을 때 사용한다.
$.get()
데이터를 서버에 HTTP GET 방식으로 전송한 후 서버 측의 응답을 받을 때 사용한다.
$.getJSON()
데이터를 서버에 HTTP GET 방식으로 전송한 후 서버측의 응답을 JSON형식으로 받을 때 사용한다.
$.getScript()
Ajax를 이용하여 외부 자바스크립트를 불러온다. 예) $(“button”).click(function(){ $.getScript(“demo_ajax_script.js”); });
.ajaxStop(function(){…})
비동기 방식으로 서버에 응답 요청이 완료되었을 때 함수가 실행된다.
.ajaxSuccess(function(){…})
ajax 요청이 성공적으로 완료되면 함수가 실행된다.
.ajaxComplete(function(){…})
ajax 통신이 완료되면 함수가 실행된다.
load() 메소드
사용자가 지정한 URL주소에 데이터를 전송하고 외부 컨텐츠를 요청하여 가져올 때 사용한다.
요청한 컨텐츠를 이용해 선택한 요소의 내용을 바꿀 수 있다.
기본형은 다음과 같다.
$(요소 선택).load(url, data, 콜백 함수)
다음 URL주소에는 외부 컨텐츠를 요청할 외부 주소를 입력하고, data에는 전송할 데이터를 입력한다.
그리고 전송이 완료되면 콜백함수에 저장된 코드가 실행된다. 이때 전송할 데이터와 콜백함수의 입력은 생략할 수
있다.
다음은 load() 함수를 사용하여 외부파일(jquery_ajax_news.html)의 일부요소를 불러오는 예제이다.
jquery_ajax_news.html
<body>
<pid="news_1">Contrary to popular belief, Lorem Ipsum is not simply random text.
It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old.</p><pid="news_2">The standard chunk of Lorem Ipsum used since the 1500s is reproduced below for those interested.</p>
</body>
1. curl_init() : cURL을 사용하기 위해 초기화 하는 메소드로, cURL 세션을 생성한다.
2. curl_setopt(세션, 옵션, 값) : 생성된 cURL 세션의 옵션을 설정한다.
옵션에 적용 가능한 값
CURLOPT_URL:접속할 url 주소 설정
CURLOPT_SSL_SERIFYPEER:SSL인증서 검사 여부 결정
CURLOPT_RETURNTRANSFER:결과값을 받을 것인지의 여부 설정
CURLOPT_HEADER:헤더 정보 출력 여부 설정
3. curl_exec():cURL 세션을 실행한다.
4. curl_close():cURL 세션을 종료한다.
다음은 웹 호스팅에서 PHP언어의 cURL 메소드를 사용해 오늘의 주요뉴스 데이터(XML)를 불러오는 예제이다.
1은 진행중(inprogress)인 첫 번째 애니메이션만 정지시킨다. 큐에 대기중인 애니메이션은 계속해서 실행한다.
2는 clearQueue, finish는 true나 false의 값을 입력할 수 있다(기본값은 false). clearQueue가 true면 큐에서
대기중인 애니메이션을 모두 제거한다. finish가 true면 진행중인 애니메이션을 강제로 종료한다.
1. 진행중인 애니메이션만 정지시키는 경우
$(".txt1").animate({opacity:0.5}, 1000)
.animate({marginLeft:"500px"}, 1000};
$(".txt1").stop();
2. 대기중인 애니메이션은 제거하고 진행중인 애니메이션은 강제로 종료하는 경우
$(".txt2").animate({opacity:0.5}, 1000)
.animate({marginLeft:"500px"}, 1000);
$(".txt2").stop(true, true);
stop() 메소드는 첫번째, 두번째 인자값(clearQueue, finish)에 따라 메소드 적용방식이 달라진다.
모든 인자값을 생략한 stop()메소드는 진행중인 애니메이션만 정지시키낟.
모든 인자값에 true를 적용하면 대기중인 애니메이션은 제거되고 진행중인 애니메이션은 강제로 종료된다.
그래서 실제로는 애니메이션이 아닌 css메소드를 적용한 것 처럼 보인다.
다음은 애니메이션 실행을 지연시키는 delay()의 기본형이다.
$("요소 선택").delay(지연시간).애니메이션 효과 메소드();
애니메이션 함수 앞에 delay(3000)메소드를 적용하면 3초 후에 애니메이션이 적용된다.
그리고 이벤트를 등록한 이후에도 동적으로 생성된 요소와 복제된 요소에도 이벤트를 등록한다.
다음은 delegate()의 기본형이다.
$([document | "이벤트 대상의 상위 요소 선택"]).delegate("이벤트 대상 요소 선택", "이벤트 종류",
function(){
자바스크립트코드;
});
one() 메소드는 이벤트가 1회 발생하면 자동으로 등록된 이벤트가 제거된다.
즉, 1회성 이벤트를 등록할 때 사용한다. one() 메소드도 등록 방식에 따라 '라이브 이벤트'의 등록이 가능하다.
다음은 one()의 기본형이다.
1. one() 기본 이벤트 등록 방식
$("이벤트 대상 선택").one("이벤트종류", function(){
자바스크립트코드;
});
2. one() 라이브 이벤트 등록 방식
$([document | "이벤트 대상의 상위 요소 선택"]).one("이벤트 종류", "이벤트 대상 요소 선택",
function(){
자바스크립트코드;
});
1. on()이벤트 해제를 위한 off()메소드
- 기본 이벤트 제거 방식
$("이벤트 대상 요소 선택").off("이벤트 종류");
- 라이브 이벤트 제거 방식
$([document | "이벤트 대상 상위 요소 선택"]).off("이벤트 종류", "이벤트 대상 요소 선택");
2. bind() 이벤트 해제를 위한 unbind()메소드
$("이벤트 대상 요소 선택").unbind("이벤트 종류");
3. delegate() 이벤트 해제를 위한 undelegate() 메소드
- 기본 이벤즈 제거 방식
$("이벤트 대상 요소 선택").delegate("이벤트 종류");
- 라이브 이벤트 제거 방식
$([document | "이벤트 대상의 상위 요소 선택"]).undelegate("이벤트 대상 선택", "이벤트 종류");
다음은 on() 메소드로 '기본 등록 방식'과 '라이브 이벤트 등록 방식'을 사용해 각각의 버튼에 이벤트를 등록하고,
이벤트 객체에는 이벤트 타입에 맞는 다양한 정보를 제공하는 속성과 메소드가 포함되어 있다.
다음은 이벤트 객체를 생성하기 위한 기본형이다.
$("이벤트 대상 선택").mousemove(function(매개변수){
매개변수(이벤트 객체), 속성;
});
다음은 이벤트 객체의 속성과 메소드 종류를 정리한 표이다.
구분
종류
설명
마우스이벤트
clientX
마우스 포인터의 X 좌표값 반환(스크롤 이동거리 무시)
clientY
마우스 포인터의 Y 좌표값 반환(스크롤 이동거리 무시)
pageX
스크롤 X축의 이동한 거리를 계산하여 마우스 포인터의 X좌표값을 반환
pageY
스크롤 Y축의 이동한 거리를 계산하여 마우스 포인터의 Y 좌표값을 반환
screenX
화면 모니터를 기준으로 마우스 포인터의 X 좌표값을 반환
screenY
화면 모니터를 기준으로 마우스 포인터의 Y 좌표값을 반환
layerX
position을 적용한 요소를 기준으로 마우스 포인터의 X 좌표값을 반환
layerY
position을 적용한 요소를 기준으로 마우스 포인터의 Y 좌표값을 반환
button
마우스 버튼의 종류에 따라 값을 반환(왼쪽:0, 휠:1, 오른쪽:2)
키보드 이벤트
keyCode
키보드의 아스키 코드값을 반환
altKey
이벤트 발생 시 Alt키가 눌렸으면 true를 아니면 false를 반환
ctrlKey
이벤트 발생 시 ctrl키가 눌렸으면 true를 아니면 false를 반환
shiftKey
이벤트 발생 시 shift키가 눌렸으면 true를 아니면 false를 반환
전체 이벤트
target
이벤트가 전파된 마지막 요소를 가리킨다
cancelBubble
이벤트의 전파를 차단하는 속성으로, 기본값은 false이며, true로 설정하면 전파가 차단
stopPropagation()
이벤트의 전파를 차단
preventDefault()
기본이벤트를 차단. 예를들어 <a>에 클릭 이벤트를 적용하고 사용자가 이벤트를 발생시키면 기본 이벤트가 등록되어 있어 링크주소로 이동하는데, 이런 기본이벤트를 차단할 수 있다.
scroll()이벤트 메소드
scroll() 메소드는 대상 요소의 스크롤바가 이동할 때마다 이벤트를 발생시키거나 강제로 scroll 이벤트를 발생시키는데
사용한다.
기본형은 다음과 같다.
1. scroll 이벤트 등록
$("이벤트 대상 선택").scroll(function(){자바스크립트 코드;});
$("이벤트 대상 선택").on("scroll", function(){자바스크립트코드;});
2. scroll 이벤트 강제 발생
$("이벤트 대상 선택").scroll();
다음은 스타일을 사용하여 스크롤바를 생성한 다음 사용자가 스크롤바를 이동시킬 때마다 이벤트가 발생되도록
포커스는 마우스로 <a> 또는 <input> 태그를 클릭하거나 Tab 키를 누르면 생성된다.
마우스 이벤트는 마우스가 없으면 사용할 수 없다. 마우스가 없다면 사용자는 키보드만 가지고 사용해야 하는데 이 때
사용자가 키보드만으로 사이트를 이용해도 불편함이 없도록 제이쿼리가 잘 작동되어야 하는데, 이를 키보드 접근성
이라 한다.
키보드 접근성을 높이기 위해서는 마우스 이벤트를 등록할 때 될 수 있으면 <a> 또는 <input> 태그에 등록하고,
키보드가 없을 경우를 고려하여 마우스 이벤트에 대응할 수 있는 키보드 이벤트까지 등록해야 한다.
focus() / blur() / focusin() / focusout() 이벤트 메소드
focus() 메소드 : 대상 요소로 포커스가 이동하면 이벤트를 발생시킨다.
blur() 메소드 : 포커스가 대상 요소에서 다른 요소로 이동하면 이벤트를 발생시킨다.
focusin() 메소드 : 대상 요소의 하위 요소 중 입력 요소로 포커스가 이동하면 이벤트를 발생시킨다.
focusout() 메소드 : 대상 요소의 하위 요소 중 입력 요소에서 외부 요소로 이동하면 이벤트를 발생시킨다.
다음은 focus()와 blur() 메소드의 기본형이다
1. focus 이벤트 등록
$("이벤트 대상 선택").focus(function(){자바스크립트코드;});
$("이벤트 대상 선택").on("focus", function(){자바스크립트코드;});
2. focus 이벤트 강제 발생
$("이벤트 대상 선택").focus();
3. blur 이벤트 등록
$("이벤트 대상 선택").blur(function(){자바스크립트코드;});
$("이벤트 대상 선택").on("blur", function(){자바스크립트코드;});
4. blur 이벤트 강제 발생
$("이벤트 대상 선택").blur();
다음은 focusin()과 focusout() 메소드의 기본형이다.
1. focusin 이벤트 등록
$("이벤트 대상 선택").focusin(funcion(){자바스크립트코드;});
$("이벤트 대상 선택").on("focusin", function(){자바스크립트코드;});
2. focusin 이벤트 강제 등록
$("이벤트 대상 선택").focusin();
3. focusout 이벤트 등록
$("이벤트 대상 선택").focusout(function(){자바스크립트코드;});
$("이벤트 대상 선택").on("focusout", function(){자바스크립트코드;});
4. focusout 이벤트 강제 등록
$("이벤트 대상 선택").focusout();
다음은 focus(), blur(), focusin(), focusout()을 이용한 예제이다.
선택한 폼 요소의 값(value)을 새 값으로 바꾼다. 그리고 포커스가 다른 요소로 이동하면 이벤트를 발생시킨다.
기본형은 다음과 같다.
1. focus 이벤트 등록
$("이벤트 대상 선택").change(function(){자바스크립트코드;});
$("이벤트 대상 선택").on("change", function(){자바스크립트코드;});
2. focus 이벤트 강제 발생
$("이벤트 대상 선택").change();
keydown()과 keypress() 이벤트 메소드는 선택한 요소에서 키보드 자판을 눌렀을 때 이벤트를 발생시키거나
해당 이벤트를 강제로 발생시킨다
두 이벤트의 차이점을 보면 keydown()은 모든키(한글 키 제외)에 대해서 이벤트를 발생시키지만 keypress()는
기능키(F1~F12, Alt, Ctrl, Shift 등)에 대해서는 이벤트를 발생시키지 않는다.
또한 키보드 이벤트 핸들러에서 생성된 이벤트 객체의 속성을 이용하면 고유 키의 코드값을 구할 수 있다.
그리고 이를 사용하여 단축키 기능을 만들수도 있다.
keyup() 메소드는 자판의 키를 눌렀다 키에서 손을 떼면 이벤트를 발생시키거나 keyup 이벤트를 강제로 발생시킨다.
다음은 keydown(), keyup(), keypress() 메소드의 기본형이다.
1. keydown 이벤트 등록
$("이벤트 대상 선택").keydown(function(){자바스크립트코드;});
$("이벤트 대상 선택").on("keydown", function(){자바스크립트코드;});
2. keydown 이벤트 강제 발생
$("이벤트 대상 선택").keydown();
3. keyup 이벤트 등록
$("이벤트 대상 선택").keyup(function(){자바스크립트코드;});
$("이벤트 대상 선택").on("keyup", function(){자바스크립트코드;});
4. keydown 이벤트 강제 발생
$("이벤트 대상 선택").keyup();
5. keypress 이벤트 등록
$("이벤트 대상 선택").keypress(function(){자바스크립트코드;});
$("이벤트 대상 선택").on("keypress", function(){자바스크립트코드;});
6. keydown 이벤트 강제 발생
$("이벤트 대상 선택").keypress();