728x90
state
- 리액트에서 state는 컴포넌트 내부에서 바뀔 수 있는 값을 의미
- state가 체인지 되면 변화를 감지하여 리렌더링을 수행
- 클래스 vs 함수형 컴포넌트에서 사용하는 방법이 다름
- 함수형 컴포넌트에서는 훅 Hook 개념을 이용해서 더욱 쉽게 사용 가능
state는 어떤 타입이건 상관x (str, number, object)
state는 여러개 가능
state는 직접 수정x (setter 사용) 강제로 수정하면 리렌더링이 들어가지 X
useState(초기값) - 함수형 컴포넌트
const [data(데이터), setData(함수)] = useState('초기값')
- 배열 반환
- 첫번쨰 배열 요소: 현재값=데이터값
- 두번째 배열 요소: 상태를 변경하는 (setter) 반환
- useState: 데이터의 초기값
실습
App.js
import StateComponent from "./component/StateComponent";
import StateComponentQ from "./component/StateComponentQ";
const App = () => {
return (
<>
<StateComponent/>
<StateComponentQ/>
</>
)
}
export default App;
stateComponent.js
- useState로 data='초기값'으로 설정 후
- return에서 버튼을 클릭하면 setData()로 변경으로 바꿈
함수 따로 안 만들고 onClick에 직접 넣어줌
- 스타일을 직접 넣어주려면 style = { }안에 { } 사용 해야 함
- 우선 color라는 state 만들고, 초기값 red로 정해줌
- color의 데이터를 스타일의 컬러 속성에 넣음
- state의 data값은 위에서 사용한 state이며, state는 여러개 사용가능
- 버튼을 누를때마다 setColor가 레드 블루 옐로우로 바뀌면서 스타일 속성이 바뀜
import { useState } from "react";
const StateComponent = () => {
/*
state란 컴포넌트에서 변화하는 값을 의미
state가 변경되면 컴포넌트를 리렌더링 시킴
함수형 컴포넌트에서는 useState()를 사용함
*/
// 함수형 컴포넌트 useState()를 사용합니다.
// let data = useState('초기값'); 콘솔로 찍었을때 data는 배열
// 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('변경');
console.log(data);
}
let enter = () => setData('입장');
let exit = () => setData('퇴장');
//state는 여러 개일 수 있습니다.
let [color, setColor] = useState('red');
// data = '1'; 이런식으로 강제로 바꾸면 리렌더링이 안 들어감 - 에러가없다는 화면을 다시 그린게 아님 !절대안됨!
return (
<>
<h3 style={{'color': color}}>state 값: {data}</h3> {/* 왼쪽은 속성명 color, 오른쪽은 위의 state의 color */}
<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 = () => {
//const로 선언하면 직접 값을 바꾸는 것 불가능
//++count로 state를 직접 수정하면 안됩니다.
const [count, setCount] = useState(0); //state, set state
return (
<div>
<h3>실습</h3>
<h3>카운트: {count}</h3>
{/* 항상 state 값을 setter 메서드를 이용해야 함 */}
<button onClick={ () => setCount(count+1)}>증가</button>
<button onClick={ () => setCount(count-1)}>감소</button>
<button onClick={ () => setCount(0)}>초기화</button>
</div>
)
}
export default StateComponentQ;
- count의 초기값이 0인 state생성
- 버튼 클릭시 setCount를 count+1로 현재 카운트에서 증가시킴
- 단, count++로 state를 직접 수정하면 리렌더링이 안됨
- 버튼 클릭시 setCount를 count-1로 현재 카운트에서 감소시킴
- 버튼 클릭시 setCount를 count를 0으로 초기화시킴
class형에서의 state의 사용
실습
App.js
import { Fragment } from "react";
import MyComponent from "./component/MyComponent";
import MyComponent2 from "./component/MyComponent2";
import MyComponent3 from "./component/MyComponent3";
/* ES6 문법 */
const App = () => {
return (
<Fragment>
<h3>App.JS</h3>
<MyComponent /> {/* 하나로 끝나는 태그, 재활용 가능 */}
{/* <MyComponent /> 주석처리 가능 */}
{/* props: 하위 컴포넌트로 전달되는 데이터 값 */}
<MyComponent name={'홍길동'} age={20} email={'aaa@naver.com'} /> {/* (1) 상위 컴포넌트에서 값을 넣고 */}
<MyComponent2 name={'이순신'} />
<MyComponent2 name={'홍길자'}/>
{/* 클래스형 props */}
<MyComponent3 name={'세종대왕'}/>
</Fragment>
)
}
export default App;
MyComponent3.js
import { Component } from "react";
class MyComponent3 extends Component { /* 리액트에서 제공하는 Component라는 모듈을 상속 받아야 함 */
/*
state는 생성자 안에서 초기화를 합니다.
state의 접근은 this.state를 이용해서 접근합니다.
state는 반드시 객체모형 이어야 합니다.
클래스형에서는 생성자를 작성할 때 반드시 props를 받고, super를 통해서 부모 컴포넌트에 연결해야 합니다.
*/
constructor(props) { //이렇게 해줘야 error를 피할 수 있음
super(props);
this.state = { //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};
state값: {this.state.b};
</>
)
}
}
export default MyComponent3;
클래스형은 다시 확인
react 이벤트 핸들링
- 이벤트 이름은 전부 카멜 표기법
- 이벤트를 전달할 때는 { 함수 } 형태로 사용
input 값 핸들링 - 실습 EventComponent.js
- input 데이터가 바뀔 때 handleName 함수 실행
- handleName 함수에서는 첫번째 매개변수에 이벤트 객체를 넣고 확인
- 3번의 target: input, target.value = input에 적은 값이 나옴
- name을 저장할 useSate 생성 - 초기값 ' '
- input이 변경될 때 handleName 이벤트 함수가 실행되면서 name이 input = e.target의 value 값으로 저장 = 사용자가 입력한 값
- input의 value={name} 적어줘야 함
클래스형 컴포넌트에서는 value를 주지 않으면 값이 나오지 않기 때문에
화면에 출력해주려고
- onKeyUp 이벤트를 넣어주고 확인해보면 key, keyCode 나옴
- if 조건문으로 e.keyCode === 13 이면 이벤트 호출
실습
App.js
import EventComponent from "./component/EventComponent";
import EventComponent2 from "./component/EventComponent2";
import EventComponentQ from "./component/EventComponentQ";
import EventComponentQ2 from "./component/EventComponentQ2";
const App = () => {
/*
p.121
이벤트 핸들링
함수형 이벤트 핸들링
*/
return (
<>
<EventComponent/>
<EventComponent2/>
{/* 실습 */}
<EventComponentQ/>
<EventComponentQ2/>
</>
)
}
export default App;
EventComponent.js
import { useState } from "react";
const EventComponent = () => {
//name을 저장할 useState
const [name, setName] = useState('');
//이벤트 함수의 첫번째 매개변수에 이벤트에 대한 정보를 넣어줍니다.
const handleName = (e) => { /* 클래스형 컴포넌트에서는 this를 막 쓸수없음, this가 가르키는 대상이 달라지기 때문 */
// console.log(e.target.value);
setName(e.target.value); //state change
}
//topic
const [topic, setTopic] = useState('');
const handleTopic = (e) => { /* 함수의 첫번째 매개변수로 이벤트 객체를 받아줌 */
setTopic(e.target.value);
}
//클릭 이벤트
const handleClick = (e) => {
alert(`${name}님의 주제는 ${topic}입니다`); //name과 topic은 현재 가리키고 있는 state 값
setName(''); //input 데이터 초기화
setTopic(''); //input 데이터 초기화
}
//엔터키의 처리
const handlePress = (e) => {
// console.log(e);
if(e.keyCode === 13) { //엔터값
handleClick(); //클릭이벤트 호출
}
}
return(
<>
<h3>리액트의 이벤트 핸들링 (input데이터)</h3>
<input type="text" name="name" onChange={handleName} value={name}/>{/* change이벤트-handleName함수 */}
<div>체인지 된 결과: {name}</div>
<input type="text" name="topic" onChange={handleTopic} onKeyUp={handlePress} value={topic}/>
<div>체인지 된 결과: {topic}</div>
<button type="button" onClick={handleClick}>click me</button>
</>
)
}
export default EventComponent;
- 버튼을 눌러주면 경고창이 뜨면서 input에 적은 이름과 주제를 보여줌
- 우선 name과 topic을 저장할 useState을 만듦
- name, topic에 onChange 이벤트가 걸리면 바로 value값을 나타내 주기 위해서 {name}, {topic}을 넣어줌
value도 넣어줘야 화면에 뿌려짐 - 각각의 input에 onChange 이벤트 걸기
함수의 첫번째 매개변수로 이벤트 객체를 받아주고, set으로 e.target.value = input에 적은 데이터값을 저장해줌 - 클릭이벤트는 onKeyUp으로 엔터의 키값이 13인데, e.keyCode = 13이면 클릭이벤트를 호출하여 실행되게 함
EventComponent2.js - 객체로
import { useState } from "react";
import EventComponent from "./EventComponent";
const EventComponent2 = () => {
//state를 객체로 관리
const [data, setData] = useState({name: '', topic: ''}); //state는 하나임
const handleChange = (e) => {
// console.log(e.target.name); //name 나옴
// console.log(data) //{name: '', topic: ''} = state는 객체
// 객체 안에서 key를 바꾸는 방법 ["키"] : 값
const copy = {...data, [e.target.name]: e.target.value }; //데이터 복사 ▶ name의 값을 사용자가 입력한 값으로 바꾸기
// console.log(copy);
setData(copy); //name state 변경
}
/*
const handleTopic = (e) => {
// console.log(e.target.name); //topic 나옴
const copy = {...data, ["topic"] : e.target.value};
setData(copy); //topic state 변경
}
*/
const handleClick = (e) => {
alert(`${data.name}님 할 일: ${data.topic}`); //객체니까 data.name, data.topic
setData({name: '', topic: ''}); //다시 초기화
}
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;
- eventComponent와 다른점은 각각의 값을 useState로 가져오는 것이 아닌 하나의 객체로 가져옴
- useState를 객체로 관리 ▶ useState({name: ' ', topic: ' '})
- 객체로 가져왔기 때문에 화면에 나타낼때도 .name, .topic 이런식으로 사용해야 함
객체 안에서 key를 바꾸는 방법
["키"] : 값
- input 값이 바뀌면 setData로 바뀐 값으로 저장해줘야 하는데 name 하나만 혹은 topic 하나만 바뀔 수 있어서 한꺼번에 바뀌면 안됨
- 그래서 copy 객체를 만드는데 ...data로 원래 객체를 가져오고, key값을 바꾸기 위해 [e.target.name] : e.target.value
여기서 name은 e.target = input 태그의 속성 name임
EventComponentQ.js
import { useState } from "react";
const EventComponentQ = () => {
const [menu, setMenu] = useState('메뉴를 선택하세요');
const handleChange = (e) => { //첫번째 매개변수는 event객체를 받겠다
if(e.target.value === '선택') { //선택을 누르면 아무것도 안 나오게 조건문
setMenu('메뉴를 선택하세요');
} else {
setMenu(e.target.value);
}
}
return(
<>
<hr/>
<h3>셀렉트 태그 핸들링 (실습)</h3>
<p>셀렉트 태그가 체인지될 때 선택한 결과를 아래에 출력</p>
<select onChange={handleChange}> {/* select 태그는 옵션이 value */}
<option>선택</option>
<option>햄버거</option>
<option>피자</option>
<option>치킨</option>
</select>
<h3>선택한 결과</h3>
<h4>{menu}</h4>
</>
)
}
export default EventComponentQ;
- select의 option이 바뀌면 바뀐 결과가 화면에 뜨게 하기
- useState로 menu 관리, {menu}로 화면에 띄워줌
- select의 이벤트 객체로 첫번째 매개변수는 event 객체를 받아서
if조건문: e.target = select, e.target.value = option 이 선택이면 메뉴를 선택하세요가 나오고
그게 아니면 setMenu로 menu에 옵션을 저장
useState 하나로 관리 (객체로 사용)
- EventComponent2.js -객체로 //실습파일과 같음
- ...form: 데이터 복사
name: "홍길동" = ["name"]: "홍길동
▶ name 값만 변경하기 위해 사용
이렇게 하는 이유는 데이터 값이 많을 때 나머지는 그대로 유지, 복사 해와서 필요한 값만 바꾸기 위해서
EventComponentQ2 내 답 - state 두개 사용
import { useState } from "react";
const EventComponentQ2 = () => {
const [data, setData] = useState('');
const handleChange = (e) => {
console.log(e.target.value); //사람이 적은 값
setData(e.target.value);
}
const [change, setChange] = useState('');
const handleAdd = (e) => {
console.log(e.target); //button나옴
const copy = [...data, e.target.value];
setChange(copy);
setData('');
}
return(
<>
<hr/>
<h3>인풋데이터 핸들링 (실습)</h3>
<p>클릭시 데이터는 공백으로 결과는 인풋이 입력한 값으로 처리</p>
<p>힌트는? 아마도 state 두 개가 필요할 듯?</p>
<input type="text" name="name" onChange={handleChange} value={data}/> {/* state는 공백인데, value값이 없으면 그게 화면에 나타나지 않음 */}
<button onClick={handleAdd}>추가하기</button>
<h3>결과</h3>
<h4>{change}</h4>
</>
)
}
export default EventComponentQ2;
- input의 value인 {data}와 결과값{change}을 state로 관리
EventComponentQ2 다른 답 - 객체 사용
import { useState } from "react";
const EventComponentQ2 = () => {
const[change, setChange] = useState({input: '', result: ''});
const handleChange = (e) => {
const copy = {...change, [e.target.name]: e.target.value};
setChange(copy); //인풋이 바뀌면 input에 입력된 데이터를 저장해서 코드를 복사해서 를 저장한다
}
const handleClick = () => {
setChange({input: '', result: change.input})
//버튼을 클릭하면 input에 입력된 값을 result에 저장하고 input은 공백으로 변경
}
return (
<>
<h3>인풋데이터 핸들링(실습)</h3>
<p>클릭시 데이터는 공백으로 결과는 인풋이 입력한 값으로 처리 <br/>
리엑트 힌트는? 아마도 state는 두개가 필요할 듯?
</p>
<input type="text" onChange={handleChange} name="input" value={change.input}></input>
<button type="button" onClick={handleClick} name="ressult">추가하기</button>
<h3>결과: {change.result}</h3>
</>
)
}
export default EventComponentQ2;
EventComponentQ2 강사님 답1 - useState 2개 사용
import { useState } from "react";
//강사님 답 1st
const EventComponentQ2 = () => {
const [data, setData] = useState(''); //인풋데이터
const [result, setResult] = useState(''); //결과데이터
const handleChange = (e) => {
setData(e.target.value); //사용자가 입력한 값 data에 저장, 비동기적으로 변경(늦게 나오는게 정상)
//console.log(data); //이전 값이 출력됩니다.
}
const handleClick = (e) => {
setResult(data); //사용자가 입력한 값으로 변경
setData(''); //인풋데이터는 공백으로 변경
}
return(
<>
<hr/>
<h3>인풋데이터 핸들링 (실습)</h3>
<p>클릭시 데이터는 공백으로 결과는 인풋이 입력한 값으로 처리</p>
<p>힌트는? 아마도 state 두 개가 필요할 듯?</p>
<input type="text" name="name" onChange={handleChange} value={data}/> {/* 핸들링 되는 data(input값) 표현해줘야 함 */}
<button onClick={handleClick}>추가하기</button>
<h3>결과</h3>
<h4>{result}</h4>
</>
)
}
export default EventComponentQ2;
- input 데이터와 결과 데이터를 state로 관리
- input에서 변경될 때 setData로 사용자가 입력한 값 data에 저장
- 버튼을 눌렀을 때 setResult로 data를 result에 저장하고 data는 공백 처리
EventComponentQ2 강사님 답2 - 객체 사용
import { useState } from "react";
//강사님 답 2nd
const EventComponentQ2 = () => {
//state를 객체로 관리
const [form, setForm] = useState({data: '', result: ''});
const handleChange = (e) => {
//data는 사용자의 입력값으로, result는 유지(form.result로 그대로 가져오기)
setForm({data: e.target.value, result: form.result});
}
const handleClick = (e) => {
//data는 '', result는 data로 변경
setForm({data: '', result: form.data});
}
return(
<>
<hr/>
<h3>인풋데이터 핸들링 (실습)</h3>
<p>클릭시 데이터는 공백으로 결과는 인풋이 입력한 값으로 처리</p>
<p>힌트는? 아마도 state 두 개가 필요할 듯?</p>
<input type="text" name="name" onChange={handleChange} value={form.data}/>
<button onClick={handleClick}>추가하기</button>
<h3>결과</h3>
<h4>{form.result}</h4> {/* 처음에는 공백이지만 나중에는 바뀔 값 */}
</>
)
}
export default EventComponentQ2;
- 객체(data, result 값)를 useState로 관리
- input의 value값이 변경될 때 setForm으로 {data: e.target.value=사용자가 입력한 값, result: form.result=state에 저장된 result값} ▶ 아직 result값을 ' ' 공백
- 버튼을 클릭하게 되면 setForm으로 {data: ' ' 공백처리, result: form.data}로 결과값은 data에 저장된 내용(사용자가 입력한 값) 저장
오늘 하루
더보기
기억에 남는 부분
-
-
어려운 부분
-
-
문제 해결 부분
-
-
728x90
'클라이언트 > React' 카테고리의 다른 글
[React] css적용 (0) | 2023.01.18 |
---|---|
[React] Component 반복, 이미지 가져오기, hook(useState, userEffect, useRef, useReduce) (0) | 2023.01.17 |
[React] node.js, spa, JSX, component, module, props (0) | 2023.01.13 |
[React] ES6, class, module export & import (0) | 2023.01.13 |
[React] ES6 문법(let, const), spread operator, Destructuring assignment, for of문, Backtick, Arrow Function(forEach, filter, map) (1) | 2023.01.12 |