43일차(2)/React(3) : map, concat 함수 / 이벤트 처리 예제
- 매번 새 프로젝트를 생성하려면 시간이 오래 걸리므로...
App00.js 를 만든 후 해당 파일을 브라우저에 출력하도록 바꾸는 방식으로 실습
App02.js
//App02.js
import { Component } from "react";
class App02 extends Component{
//상태값(state) 정의하기
state={
info:"x:0, y:0",
info2:"x:0, y:0"
};
render(){
//요소에 적용할 인라인 css를 object로 정의하고 적용할 수 있다.
const boxStyle={
width:"300px",
height:"300px",
border:"1px solid red",
backgroundColor:"yellow" //여러 단어로 구성된 속성은 camel case를 사용한다.
};
return(
<div className="container">
<h3>마우스 이벤트 처리</h3>
{/*
이벤트리스너 함수에 전달되는 이벤트 객체는 react가 넣어주는 이벤트 객체이다.
original 이벤트 객체를 사용하고 싶다면
e.nativeEvent 를 사용하면 된다.
*/}
<div style={boxStyle} onMouseMove={(e)=>{
console.log(e);
//마우스의 좌표를 이용해서 문자열을 만들어낸 다음
let info=`x:${e.clientX}, y:${e.clientY}`;
//state를 update한다.(state를 사용하는 UI는 자동 update 된다.)
this.setState({info:info});
}}></div>
{/* state 값을 활용해서 출력하기 */}
<p>{this.state.info}</p>
{/* 이벤트 처리를 할 함수를 미리 만들어 놓고 이벤트 리스너 함수로 등록하기 */}
<div style={boxStyle} onMouseMove={this.handleMouseMove}></div>
<p>{this.state.info2}</p>
</div>
);
}//render()
//mouseMove 이벤트를 처리할 함수
handleMouseMove = (e)=>{
//마우스의 좌표를 이용해서 문자열을 만들어낸 다음
let info=`x:${e.clientX}, y:${e.clientY}`;
//state를 update한다.(state를 사용하는 UI는 자동 update 된다.)
//여기서 this가 App2 Component를 참조하게 하려면 이 함수는 화살표함수로 만들어져 있어야 한다.
this.setState({info2:info});
}
}//class App02
export default App02;
- 마우스 이벤트 처리하기
- src에 새로 만든 app02가 화면에 나오게 하려면?
→ 밑에 export default App02; 추가하고 index.js에서 App02로 수정
onMouseMove{(e)=>{ }}
- 함수명은 카멜케이스로 적어주기
- 이벤트객체 e를 함께 전달
- 이벤트객체 e가 콘솔에 인쇄되는데, react에서 한번 조작한 이벤트객체가 출력된다.
- 여기에는 offSetX,Y는 없다
- react에서 한번 조작한것이기 때문에 그렇다.
- offSetX,Y는 nativeEvent 안에 있으므로, 원본 이벤트객체를얻고 싶다면 nativeEvent 를 사용하면 된다.
- 이 마우스 포인터의 좌표값을 출력하려면 model이 필요하다
- react에서는 모델을 state { } 에서 관리한다.
- state를 정의한다. state 안의 info라는 방에 변수 x, y 를 넣어준다.
- render 바깥에다가 정의해야 한다!
- 이것을 render 안에서 {this.state.info} 형태로 출력하면 된다.
- 현 상태에서는 이렇다! offset 값이 적용되지는 않음
- {this.state.info} 출력하기 전에
info 안의 문자열을 재지정하고, state를 업데이트해주면 된다.(UI는 자동 업데이트됨)
- state에서 초기값을 0으로 지정하고, 그 값을 계속 바꿔주는 형태로 작성!
- component 안의 setState 함수는
기존에 있는 info(모델의 값)를 새로운 info 로 업데이트하는 함수이다.
- 이벤트 처리를 할 메소드를 미리 만들어 놓고 이벤트 리스너 함수로 등록하기
- 함수명을 만들어놓고 새 함수를 아래에서 등록하기
- render 바깥에서, class App02 안쪽에서 함수를 만들어야 한다.
- handleMouseMove 함수생성(위와 같은 내용)
- 박스2 안에서 마우스 움직임이 일어나면 info에서 읽어와서 info2가 state를 업데이트하게된다.
handleMouseMove(e){ }
- 그러나! 이렇게 만들면 this가 가리킬 수가 없다.
- render는 (){} 으로 만들어도 되지만 다른 함수를 만들 때에는 화살표함수로 만드는 것이 좋다.
- (e)=>{ } 가 handleMouseMove 안에 대입되는 구조이다.
- handleMouseMove가 하나의 필드이고, 여기에 함수가 들어간 것이라고 생각하면 된다.
App03.js
//App03.js
import { Component } from "react";
class App03 extends Component{
render(){
/*
배열에 jsx객체를 여러개 넣기
*/
const names=[];
names.push(<li key={0}>바나나</li>);
names.push(<li key={1}>딸기</li>);
names.push(<li key={2}>복숭아</li>);
//jsx객체를 만들어낼 아이템이 배열에 준비되어 있다고 가정하자
const animals=["강아지", "코끼리", "고양이"];
//만들어낼 jsx 객체를 저장할 빈 배열을 만든다.
const result=[];
//반복문 돌면서
for(let i=0; i<animals.length; i++){
//동물 이름이 출력된 jsx객체를 만들어서
let tmp=<li key={i}>{animals[i]}</li>;
//미리 준비된 배열에 누적시키기
result.push(tmp);
}
//배열의 map() 함수를 활용해서 jsx객체가 들어있는 새로운 배열을 얻어내기
const result2= animals.map((item, index)=>{
return <li key={index}>{item}</li>
});
return(
<div className="container">
<h3>반복문 돌면서 여러 개의 문서 객체 만들기</h3>
<ul>
{names}
</ul>
<h3>동물 목록</h3>
<ul>
{result}
</ul>
<h3>동물 목록2</h3>
<ul>
{result2}
</ul>
</div>
);
}
}
export default App03;
- names배열을 만들고, names.push() 안에 <li>를 넣어서 배열에 담는다.
- 출력은 되지만, 콘솔창에 각각의 child는 key property가 필요하다는 경고 창이 뜬다.
- 인덱스 키를 넣어줌. 만약 DB라면 primary key를 넣어주면 될 것
const result=[];
for(let i=0; i<animals.length; i++){
result.push(<li key={i}>{animals[i]}</li>)
}
const result=[];
//반복문 돌면서
for(let i=0; i<animals.length; i++){
//동물 이름이 출력된 jsx객체를 만들어서
let tmp=<li key={i}>{animals[i]}</li>;
//미리 준비된 배열에 누적시키기
result.push(tmp);
}
- 같은것이다. 첫번째 작성 방식에 익숙해지기
- map() : 배열 내의 모든 요소 각각에 대하여 주어진 함수를 호출한 결과를 모아 새로운 배열을 반환하는 함수
- map() 이라는 함수는 새로운 배열을 리턴해준다.
- Array를 사용해서 새로운 배열(map1)을 얻어낸다. 기존 Array의 아이템을 활용해서!
- 각각의 아이템을 어떻게 활용할지 작성하면 된다.
- 위 예제는 2를 곱한 값을 이용해서 새로운 배열을 만들어낸다는 뜻!
*map 설명 : 링크
- map1과 map2의 작성법 비교. 함수 안에 따로 로직이 없으면 리턴할 값만 들어가면 된다.
- (item, index)로 입력하면 아이템과 인덱스까지 함게 전달할 수 있다.
<li key={ }>
- react에서 배열을 출력하려면 하나마다 유일한 키값이 부여되어야 한다.
- map 함수 중요하다! 새로운 배열을 얻어낸다는 점에 유의하기
App03_ex1.js
//App03_ex1.js
import { Component } from "react";
class App extends Component{
state={
index:0,
msgs:[]
};
render(){
return(
<div className="container">
<h1>문서 객체 동적으로 만들기</h1>
<input type="text" onKeyUp={this.handleKeyUp} />
<ul>
{this.state.msgs}
</ul>
</div>
);
}
//input요소에 KeyUp이벤트가 일어날 때마다 호출되는 함수
handleKeyUp=(e)=>{
console.log(e);
//만일 Enter Key를 눌렀다면
if(e.keyCode==13){
//입력한 문자열 읽어오기(이벤트가 일어난 input 요소의 value 값)
let msg=e.target.value;
//아래와 같이 배열에 아이템을 추가한다고 해서 UI가 update되지는 않는다.
//this.state.msgs.push(<li>msg</li>)
//아이템이 추가된 새로운 배열을 얻어내서 setState() 해야 한다.
let newArray = this.state.msgs.concat(<li key={this.state.index}>{msg}</li>);
this.setState({
msgs:newArray,
index:this.state.index+1
});
}
}
}
export default App;
<input type="text" onInput={this.handleInput} />
- input요소에서 뭔가 입력되었을 때 this.handleInput 함수가 호출되도록!
- 이벤트 객체 전달되게 하기
- 그런데 이렇게 하면 엔터는 작동되지 않는다. 입력되는 것이 아니라서...
<input type="text" onKeyUp = {this.handleKeyUp} />
- 이럴 땐 onInput 대신 onKeyUp을 사용
- Enter도 인식되는 것을 확인할 수 있다.
- 콘솔에서 Enter의 키코드가 13번이라는 것을 알아낼 수 있다.
- input 요소가 뭔가를 입력하고 엔터를 치면 입력한 내용을 msgs의 배열에 추가하도록 할 예정!
- 이렇게 작성하면 추가가 되지 않는다. UI가 업데이트되지 않는다.
(vue의 경우 배열의 item이 수정되면 UI에 자동 반영이었는데, react에서는 아니다)
- 구글에서 javascript 배열 concat 검색
* concat() 함수 설명 : 링크
- 2개의 배열을 합치면 새로운 배열이 나온다.
- 배열이 아닌, 아이템만 넣어도 적용된다. (array2)
if(e.keyCode==13){
let msg=e.target.value;
let newArray = this.state.msgs.concat(<li>{msg}</li>);
this.setState({msgs:newArray});
}
- concat 안에 msg를 리스트로 만들어서 출력.
- 엔터를 누르면 배열에 입력되긴 하는데 unique key 값이 없어서 경고 발생
if(e.keyCode==13){
let msg=e.target.value;
let newArray = this.state.msgs.concat(<li key={this.state.index}>{msg}</li>);
this.setState({
msgs:newArray,
index:this.state.index+1
});
}
- this.state.index를 넣어주고, setState할 때 msgs뿐만 아니라 index도 하나씩 값을 증가시켜주면 된다.
- 엔터 할때마다 새로운 리스트가 생겨난다.
- state에 들어 있는 내용은 이 object의 특정 방에 있는 내용을 끊임없이 새로운 값으로 교체하는 느낌이다.
- .setState() 를 사용해 state에 새로운 데이터를 담으면 UI는 자동으로 업데이트 된다.
App03_ex2.js
- input요소에서 값 받아서 전달하기
//App03_ex2.js
import { Component } from "react";
class App extends Component{
state={
index:0,
msgs:[]
}
render(){
return(
<div className="container">
<h1>동적으로 문서 객체 만들기2</h1>
{/*
input 요소가 초기화되는 시점에 ref={ 함수 } 안에 있는 함수가 호출되면서
input 요소의 참조값이 함수의 매개변수에 전달된다.
매개변수에 전달된 값을 필드에 저장하면 추후에 필요한 시점에 사용할 수 있다.
*/}
<input type="text" placeholder="메세지 입력" ref={(ref)=>{
console.log(ref);
//ref 에 담긴 참조값을 inputText라는 이름의 필드에 저장하기
this.inputText=ref;
}}/>
<button onClick={this.handleClick}>전송</button>
<ul>
{this.state.msgs}
</ul>
</div>
);
}
//버튼을 눌렀을때 호출되는 함수
handleClick = ()=>{
//입력한 메세지 읽어오기
let msg=this.inputText.value;
let newArray=this.state.msgs.concat(<li key={this.state.index}>{msg}</li>)
//상태값을 변경해서 UI를 업데이트한다.
this.setState({
index:this.state.index+1,
msgs:newArray
});
}
}
export default App;
- 이번에는 input요소가 아니라 버튼 요소에 이벤트가 일어났을때 input 요소에 들어온 값을 읽어오는 것.
- 일반 javascript라면 document.querySeletor("id") 로 읽어오겠지만,
react에서는 component에 id를 부여하는 것은 좋지 않다.
- 그러면 어떻게 읽어오는지? → ref 를 사용한다.
- ref : 레퍼런스 값과 관련된 react의 기능
- 이 input 요소가 초기화될때 이 input 요소 안의 참조값이 전달되면서 함수가 호출된다.
- 새로고침 해보면 뭔가 console 창에 전달되는 것을 볼 수 있다. 아직 아무것도 입력하지 않았어도!
- UI가 초기화되는 시점에 ref 라는 함수에 input 요소의 참조값이 전달된다.
- 다른 곳에서 이 input요소의 참조값이 필요하다면 this.inputText 하면 된다.
아까 ref가 저 안에 저장해놨기 때문에!
- ref 를 사용해서 담아놓은 것을 아래에서 호출해서 msg안에 담아주기!
- state 안에 index:0, msgs:[] (빈 배열)을 준비해주고, <ul> 안에 msgs를 출력한다.
- 마지막으로 this.setState를 사용해 state 값을 업데이트해주면 된다.
'국비교육(22-23)' 카테고리의 다른 글
44일차(1)/React(5) : React 저장소 clone하기 / React 코드 리뷰 (0) | 2022.12.08 |
---|---|
43일차(3)/React(4) : filter 함수 / 자식 component 활용 예제 (1) | 2022.12.08 |
43일차(1)/React(2) : React App 생성, React 기초 (1) | 2022.12.07 |
42일차(3)/React(1) : Node.js 초기 세팅, 주요 개념 정리 (0) | 2022.12.06 |
42일차(2)/JSTL(2) : java 코드로 작성된 페이지 JSTL로 작성하기 (0) | 2022.12.06 |