1. state
- 리액트에서 state는 컴포넌트 내부에서 바뀔 수 있는 값을 의미합니다
- state가 체인지 되면 변화를 감지하여 리렌더링을 수행합니다.
- 클래스 vs 함수형 컴포넌트에서 사용하는 방법이 다릅니다.
- 함수형 컴포넌트에서는 훅 Hook개념을 이용해서 더욱 쉽게 사용 가능 합니다.
* 나의 첫번째 훅
- useState(초기값)
- useState() : 배열 반환
- 첫번째 배열의 요소에는 현재 값을, 두번째 요소는 상태를 변경하는 (setter)-function을 반환합니다
const [data, setData] = useState('초기값')
- state는 어떤 타입이던 상관 없습니다. (str, number, object)
- state는 여러개 일 수도 있습니다.
- state는 직접 수정하면 안 됩니다. setter를 사용하세요!
const StateComponent = () => {
const [msg, setData] = useState('초기값')
const enter = () => setData('입장했습니다')
const exit = () => setData('퇴장했습니다')
return (
<div>
<h3>{msg}</h3>
<button onClick={enter}>입장</button>
<button onClick={exit}>퇴장</button>
</div>
)
}
* 예제(app.js, stateComponent.js)
import { Fragment } from "react";
import StateComponent from "./component/StateComponent"
const App = () => {
return (
<>
<StateComponent/>
</>
)
}
export default App;
import { useState, setdata } from "react";
const StateComponent = () => {
/*
p.103
state란 컴포넌트에서 변화하는 값을 의미합니다.
state가 변경되면 컴포넌트 리렌더링을 시킵니다.
함수형컴포넌트에서는 useState()를 사용합니다.
*/
//함수형 컴포넌트에서는 useState()를 사용합니다
// 1st
// let data = useState('초기값');
// console.log(data);
// let a = data[0];
// let b = data[1];
//2nd
let [data, setData] = useState("초기값");
// console.log(data); //state값
// console.log(setData); //state setter 함수
let func = () => setData("변경")
let enter = () => setData("입장")
let exit = () => setData("퇴장")
// state는 여러개 일 수 있습니다.
let [color, setColor] = useState("red");
return (
<>
<h3 style={{'color': color}}>state값: {data}</h3>
<button onClick={func}>값 변경하기</button>
<button onClick={enter}>입장</button>
<button onClick={exit}>퇴장</button>
<hr/>
<button onClick={() => setColor("red")}>붉은색</button>
<button onClick={() => setColor("blue")}>푸른색</button>
<button onClick={() => setColor("yellow")}>그 사이 3초 그 짧은 색</button>
</>
)
}
export default StateComponent;
* StateComponentQ.js
import { useState } from "react";
const StateComponentQ = () => {
//++count로 state를 직접 수정하면 안됩니다.
const [count, setCount] = useState(0); //state, set state
return (
<div>
<h3/>
<h3>실습</h3>
<div>카운트 : {count} </div>
<button onClick={() => setCount(count+1)}>증가</button>
<button onClick={() => setCount(count-1)}>감소</button>
<button onClick={() => setCount(0)}>초기화</button>
</div>
)
}
export default StateComponentQ;
* 수정된 MyComponent3.js
import { Component } from "react";
class MyComponent3 extends Component {
/*
state는 생성자 안에서 초기화를 합니다.
state의 접근은 this.state를 이용해서 접근합니다.
state는 반드시 객체 모형이어야 합니다.
클래스형에서 생성자를 작성할 때는 반드시 props를 받고 super를 통해서 부모 컴포넌트에 연결해야 합니다.
*/
constructor(props){
super(props);
this.state = {
a : 1,
b: props.name //부모로부터 전달받은 name
}
}
//클래스형 컴포넌트는 render 함수 안에서 return문을 작성
render(){
let {name} = this.props; //props
// console.log(name);
return(
<>
<hr/>
<div>나의 클래스형 컴포넌트</div>
state값: {this.state.a}<br/>
state값: {this.state.b}<br/>
</>
)
}
}
export default MyComponent3;
2. 리액트 이벤트 핸들링(p.121)
1) 이벤트 규칙
- 이벤트의 이름은 전부 카멜 표기법으로 표현됩니다. ex) onkeyup -> onKeyUp
- 이벤트를 전달할 때는 {함수} 형태로 사용합니다.
2) 인풋값 핸들링 해보기
- 인풋의 값이 변화되는 이벤트 onChange 연결
- 이벤트 안 첫번째 매개변수에서 event 객체 활용하기(e.target.속성값)
- setter를 이용해서 state 변경하기
- useState를 하나로 관리하기(객체로 사용)
const EventComponent = () => {
const [name, setName] = useState('');
let handleName = (e) => { //2.event객체 활용
setName(e.target.value); //3.state변경 (input의 value도 변경)
}
return (
<div>
<h3>리액트 이벤트 핸들링</h3>
<input type="text" name="name" onChange={handleName} value={name}/><br/> {/*1. 이벤트연결*/}
<h3>체인지된 결과: {name}</h3>
</div>
)
}
* EventComponent.js, EventComponentQ.js
import { useState } from "react";
const EventComponent = () => {
//name을 저장할 useState
const [name, setName] = useState('')
//이벤트 함수의 첫번째 매개변수에 이벤트에 대한 정보를 넣어줍니다.
const handleName = (e) => {
// console.log(e.target.value);
setName(e.target.value); //state 체인지
}
//
const [topic, setTopic] = useState('');
const handleTopic = (e) => {
setTopic(e.target.value);
}
//클릭 이벤트
const handleClick = (e) => {
alert(`${name}님의 주제는 ${topic}입니다.`); //state값
setName(''); //인풋 데이터의 초기화
setTopic(''); //인풋 데이터의 초기화
}
//엔터키의 처리
const handlePress = (e) => {
// console.log(e);
if(e.keyCode === 13){ //엔터값
handleClick();
}
}
return (
<>
<h3>리액트의 이벤트 핸들링(인풋 데이터)</h3>
<input type="text" name="name" onChange={handleName} value={name} />
<div>체인지 된 결과 : {name} </div>
<input type="text" name="topic" onChange={handleTopic} onKeyUp={handlePress} value={topic} />
<div>체인지 된 결과 : {topic} </div>
<button type="button" onClick={handleClick}>클릭 미</button>
</>
)
}
export default EventComponent;
import { useState } from "react";
const EventComponentQ = () => {
const [data, setData] = useState('메뉴를 선택하세요');
//셀렉트 태그에서는 option 태그가 기본 value가 됩니다.
const handleChange = (e) => {
console.log(e.target.value);
setData(e.target.value); //state 체인지
}
return(
<div>
<hr/>
<h3>셀렉트 태그 핸들링(실습)</h3>
<select onChange={handleChange}>
<option>피자</option>
<option>햄버거</option>
<option>치킨</option>
</select>
<h3>결과: {data}</h3>
</div>
)
}
export default EventComponentQ;
* EventComponent2.js
import { useState } from "react";
import EventComponent from "./EventComponent";
const EventComponent2 = () => {
//state를 객체로 관리
const [data, setData] = useState({ name: '', topic: ''}) //객체
const handleChange = (e) => {
//객체 안에서 key를 바꾸는 방법 ["키"]: 값
const copy = { ...data, [e.target.name]: e.target.value }; //복사해서 기존 데이터를 가져옴
// console.log(copy);
setData(copy); //state 변경
console.log(copy);
}
/*
const handleTopic = (e) => {
console.log(e.target.name);
const copy = {...data, [e.target.name] : e.target.value}; //데이터 복사
setData(copy);
}
*/
const handleClick = (e) => {
alert(`${data.name}님 할일: ${data.topic}`);
setData({name: '', topic: ''}); //state 초기화
}
return (
<>
<h3>리액트 이벤트 핸들링(객체로)</h3>
<input type="text" name="name" onChange={handleChange} value={data.name} />
<h3>결과: {data.name}</h3>
<input type="text" name="topic" onChange={handleChange} value={data.topic} />
<h3>결과: {data.topic}</h3>
<button type="button" onClick={handleClick}>click me!</button>
</>
)
}
export default EventComponent2;
* EventComponentQ2(내 답안, 선생님 답안)
import { useState } from "react";
import EventComponent from "./EventComponent";
const EventComponentQ2 = () => {
//state를 객체로 관리함
const [data, setData] = useState({ name: '', topic: ''});
const handleChange = (e) => {
//앞에는 data의 객체를 모두 가지고 와서 뒤에 바꾸는 방법을 통해 name 값을 입력된 값으로 변경해줌
//객체 안에서 key를 바꾸는 방법 ["키"]: 값
const copy = { ...data, ['name']: e.target.value}; //복사해서 기존 데이터를 가져옴
setData(copy); //state 변경
}
//클릭을 하면 name값을 공백으로, result를 data.name(저장된 data의 이름값)으로 변경: 키가 같으면 내용을 덮어쓸 수 있음
const handleClick = (e) => {
//console.log(data.name);
//객체를 가져와서 name만 초기화(), 수정
const copy = {...data, ['name']: '', ['result']: data.name}
setData(copy); //state 변경
}
return (
<>
<h3>인풋 데이터 핸들링(실습)</h3>
<h5>클릭시 데이터는 공백으로 결과는 인풋이 입력한 값으로 처리
힌트는? 아마도 state는 두개가 필요할 듯?
</h5>
<input type="text" onChange={handleChange} value={data.name} />
<button type="button" onClick={handleClick}>추가하기
</button>
{/* data.name을 result에 저장했으니까 data.result를 가지고 오면 그 값이 적용됨. */}
<h3>결과: {data.result}</h3>
</>
)
}
export default EventComponentQ2;
import { useState } from "react";
import EventComponent from "./EventComponent";
const EventComponentQ2 = () => {
//state를 객체로 관리함
const [data, setData] = useState(''); //인풋 데이터
const [result, setResult] = useState(''); //결과 데이터
const handleChange = (e) => {
setData(e.target.value); //비동기적으로 변경
console.log(data); //이전 값이 출력 됩니다(정상)
}
const handleClick = (e) => {
setResult(data); //사용자가 입력한 값으로 변경
setData(''); //인풋 데이터는 공백으로 변경
}
return (
<>
<h3>인풋 데이터 핸들링(실습)</h3>
<pre>클릭시 데이터는 공백으로 결과는 인풋이 입력한 값으로 처리</pre>
<pre>힌트는? 아마도 state는 두개가 필요할 듯? </pre>
<input type="text" onChange={handleChange} value={data}/>
<button type="button" onClick={handleClick}>추가하기</button>
<h3>결과: {result}</h3>
</>
)
}
export default EventComponentQ2;
import { useState } from "react";
import EventComponent from "./EventComponent";
const EventComponentQ2 = () => {
//state를 객체로 관리
const [form, setForm] = useState({ data: '', result: '' }); //인풋 데이터
const handleChange = (e) => {
//data는 사용자의 입력 값으로, result는 유지
setForm({ data: e.target.value, result: form.result })
}
const handleClick = (e) => {
//data는 '', result는 data로 변경
setForm({ data: '', result: form.data})
}
return (
<>
<h3>인풋 데이터 핸들링(실습)</h3>
<pre>클릭시 데이터는 공백으로 결과는 인풋이 입력한 값으로 처리</pre>
<pre>힌트는? 아마도 state는 두개가 필요할 듯? </pre>
<input type="text" onChange={handleChange} value={form.data} />
<button type="button" onClick={handleClick}>추가하기</button>
{/* form의 result(객체의 값 불러올 때) */}
<h3>결과: {form.result}</h3>
</>
)
}
export default EventComponentQ2;
3. 컴포넌트 반복
- 목록 요소들을 반복처리 할때는 map함수를 이용 합니다.
- 반복 컴포넌트에는 반드시 key props를 전달해야 합니다.
- map함수는 실행한 결과를 가지고 새로운 배열을 만들 때 사용
array.map(callbackFunction(currenValue, index, array), thisArg)
- currenValue: 현재값
- index: 현재인덱스
- arrayt: 현재배열,
- thisArg: callbackFunction 내에서 this로 사용될 값
const IterationComponent = () => {
const arr = [1,2,3,4,5];
const newArr = arr.map( item => item*10 ) // => 한줄일 경우 리턴
console.log('map으로 생롭게 만들어진 newArr', newArr)
return (
....
)
}
* IteratonComponent.js
const IterationComponent = () => {
//1. 반복 처리
const arr = [1, 2, 3, 4, 5];
//es5
// const newArr = arr.map(function(item, index, arr) {
// return item * 10;
// })
//es6 = es5와 같은 표현입니다.
// const newArr = arr.map((item, index, arr) => item * 10);
// console.log(newArr);
//2. 반복 처리(태그)
//리액트에서 반복 처리 시에 key를 태그에 작성합니다. (key는 고유한 값입니다.)
//key는 화면에서 렌더링 할 때 변화를 감지하기 위해 참조하는 값입니다.
const newArr = arr.map( (item, index) => <li key={index}>{item}</li> );
console.log(newArr);
return (
<>
<ul>
{newArr}
{/* 같은 표현입니다 */}
{/* {arr.map( (item, index) => <li key={index}>{item}</li> )} */}
</ul>
</>
)
}
export default IterationComponent;
- map의 콜백함수의 리턴에 반복시킬 태그를 넣습니다.
- 리액트에서 key는 배열을 렌더링 시킬때 빠르게 변화를 감지하기 위해 사용하는 속성입니다.
- key는 index대신 고유한 값을 넣어 주도록 권유 됩니다. (key를 넣지 않으면 props에러가 발생 됩니다.)
- 반복할 요소를 state에 넣고 처리하기, 버튼 클릭시 인풋state의 값을 목록state에 추가하기
1) 반복처리할 state선언
2) input state, 인풋 핸들러선언
3) 버튼 클릭시 input state의 값을 목록state에 추가
import { useState } from "react";
const IterationComponent2 = () => {
//1. 반복처리할 데이터 state
const data = [{id:1, topic: 'hello'},
{id:2, topic: 'bye'}
];
const [list, setList] = useState(data)
const newData = list.map( item => <li key={item.id}>{item.topic}</li> )
//2.인풋핸들러추가
const [inputData, setInputData] = useState('')
const handleChange = e => {
setInputData(e.target.value) //input데이터 state로 관리
}
//3. 데이터 추가시 input의 값으로 1번 데이터 수정
const handleClick = e => {
let obj = {id: list[list.length-1].id + 1 , topic: inputData} //추가할데이터(마지막요소의 id+1, 인풋데이터)
let newList = list.concat(obj) //state와 추가할 데이터 합치기(배열합치기)
setList(newList); //state업데이트
setInputData(''); //input값 비우기
}
return (
<div>
<hr/>
<input type="text" onChange={handleChange} value={inputData}/>
<button onClick={handleClick}>추가하기</button>
<ul>
{newData}
</ul>
</div>
)
}
export default IterationComponent2;
* IterationComponent2.js
import { useState } from "react";
const IterationComponent2 = () => {
//1. 반복할 데이터 (state로 관리)
const arr = [
{ id: 1, topic: 'hello' },
{ id: 2, topic: 'bye' },
{ id: 3, topic: 'see you' },
];
const [list, setList] = useState(arr);
//2. map 함수를 이용해서 li 태그로 생성
const newList = list.map(item =>
<li key={item.id} onDoubleClick={ () =>
handleRemove(item.id)}> { /* 함수 안에서 함수 호출 */}
{item.topic}
</li>
)
//3. 인풋 데이터 관리(data에 값 저장)
/* 스테이트 선언 */
const [data, setData] = useState('');
const handleChange = (e) => {
setData(e.target.value);
}
//4. 추가하기 버튼 클릭시 input의 값을 list 마지막에 추가
//list[2].id 값에 + 1 해주면 4가 됨
const handleClick = (e) => {
let obj = { id: list[list.length - 1].id + 1, topic: data };
// list.push(obj); //정상 작동 불가(state 절대로 직접 변경하면 안됨)
let newArr = list.concat(obj); //원본 리스트를 수정하지 않고, 합쳐친 새로운 리스트를 반환(리스트에 obj에 합쳐진 새로운 리스트 반환)
setList(newArr); //state 변경
setData(''); //사용자의 입력 값(input) 초기화
}
//5. 삭제 기능(더블 클릭이면 삭제)
//아래에 두면 호이스팅 때문에 화살표 함수 쓰면 오류 발생하기 때문에 위로 올려줘야 함. (화살표 함수는 익명함수기 때문에 호이스팅이 불가합니다.)
//아니면 위에 doubleClick 옆에 그냥 함수로 넣어도 가능
// <li key={item.id} onDoubleClick={ () => console.log(1)}>
//이벤트 안에서 함수를 호출로 연결하는 방법을 사용함
// onClick = { () => 함수() }
const handleRemove = (a) => {
// console.log(a); //키
//id가 필요함
//filter(리턴 값이 true, false) - 콜백의 리턴이 true인 값을 가지고 새로운 배열을 생성
// const ex = [1,2,3,4,5].filter( (item) => item != 3)
// console.log(ex);
const newList = list.filter( item => item.id !== a);
setList(newList);
}
return (
<>
<h3>목록 추가하기</h3>
<input type="text" onChange={handleChange} value={data} />
<button type="button" onClick={handleClick}>추가하기</button>
<ul>
{newList}
</ul>
</>
)
}
export default IterationComponent2;
'TIL > React' 카테고리의 다른 글
day70-react (0) | 2023.01.19 |
---|---|
day69-react (0) | 2023.01.18 |
day68-react (0) | 2023.01.18 |
day67-react (0) | 2023.01.17 |
day65-react (0) | 2023.01.13 |