생각기록
2023-01-05 React state 본문
state
- 중요한 개념!!
- 특수한 기능을 하는 변수
- 상태를 의미 ㅡ> 즉, 리액트에서 컴포넌트에 대한 상태를 의미
- 사용 이유? > state가 변경되면 해당 컴포넌트는 다시 리랜더링되어 컴포넌트의 유동성 관리가 쉽다.
이게 왜 중요해?
리액트는 부드러운 화면전환
버츄얼 돔 사용해서 특정 컴포넌트만 랜더링해서 새로고침 없이 빠른 화면전환이 장점이라했는데
그것을 관리해주는 것이 이 state입니다.
오류 1 > eslint와 리엑트가 충돌 오류
해결

state React 관련 팁
설치하면, 리액트 관련 자동완성 기능 만들어준다.
Ex1.js 파일
rfc라고 치면, 파일이름 기반으로 function이 생긴다.
파일명과 동일하게 컴포넌트 구성해준다.
*리액트에서 컴포넌트를 구성할때 return요소는 하나의 부모요소로 감싸져야 합니다.
다른 컴포넌트들과 어떤 관계인지 알기 힘들기 때문에
부모요소 하나로만 감싸져야 합니다.
즉 <div>하나로만 전체 감싸기!
이제 state값을 선언해줍시다.
State 체험 해보기
효석님은 변화 없고, 콘솔은 변화 있다.
<span>의 teacher라는 변수는
JS적으로는 변화했지만, 웹에서는 변경이 안되고 있다.
이유는?
1. 새로고침이 안되었기 때문이다.
2. 이전처럼 돔요소로 접근을 안해서다..
JS적으로 이것을 영어로 변경하려면 ?
돔적으로 접근했더니... 이전처럼 변경은 됩니다.
리엑트는 컴포넌트 적으로 변화가 자주 일어나는 곳에서 사용하면 좋다.
하지만 돔적 접근을 하면, 그 전과 다를바 없겟죠
그것을 위해 나타난
useState
1. 앞서 state가 변경되면 = 컴포넌트의 상태가 변경이 되면
2. 리액트에서는 해당 부분을 바로 리랜더링 (다시 그려주기) 한다
리액트에서는 useState를 hook이라고 부른다. hook중 하나
App이라는 컴포넌트가
영어로! 를 클릭 시
상태 변경 함수인 setTeacher('sunam')으로
'수남' 초기 상태값이
변경 함수로 'sunam'이 됩니다.
이렇게 변경이 되면, 컴포넌트가 변경되었기 때문에 리랜더링이 되어 실시간으로 변화합니다.
useState 문법!
import { useState } from 'react';
function App() {
// 1. useState 사용 두번째가 함수처럼 쓰인다.
const [teacher, setTeacher] = useState('수남');
function inEnglish() {
const spanEl = document.querySelector('.App > span ');
spanEl.innerHTML = 'tetz';
// teacher = 'tetz';
// console.log(teacher);
}
return (
<div className="App">
<button onClick={() => setTeacher('sunam')}>영어로!</button>
<br />
<span>{teacher}</span>
</div>
);
}
export default App;
import { useState } from "react";
const [스테이트이름, 스테이트변경함수] = useState(초기값);
1. 상태를 관리하는 state를 배열의 첫번째로 정해주고, 해당 state를 변경 할 수 있는 함수를 두번째로 지정함
- teacher라는 스테이트 변수
- setTeacher > 스테이트 값을 변경할수 있는 함수
- useState('수남') 초기값
<span>{teacher}</span>
클릭을 하기전엔 초기값이 들어가있다.
state변경 함수
setTeacher('sunam') 변경해주고 싶은 값을 넣는다.
클릭을 하면서 이 hook이 컴포넌트를 리랜더링 하기 때문에 변화값이 바로 변화가가 되는것
여기서 컴포넌트는 APP(){ } 이다.
2. 동작 원리
state 상태가 이전의 값과 다르면 > 해당 컴포넌트를 다시 랜더링
즉 '수남' 초기값이 > 'sunam'으로 값이 변경되어 해당 html을 다시 리랜더링 함
바로 활용해보자면
import { useState } from 'react';
function App() {
// 1. useState 사용 두번째가 함수처럼 쓰인다.
const [pororo, setPororo] = useState('뽀로로');
function inEnglish() {
const spanEl = document.querySelector('.App > span ');
spanEl.innerHTML = 'tetz';
// teacher = 'tetz';
// console.log(teacher);
}
return (
<div className="App">
<button onClick={() => setPororo('Pororo')}>영어로!</button>
<br />
<span>{pororo}</span>
</div>
);
}
export default App;
활용2 > 리랜더링이 발생하지 않는 코드
import { useState } from 'react';
function App() {
// 1. useState 사용 두번째가 함수처럼 쓰인다.
let [teacher, setTeacher] = useState('선생님');
function customSetTeacher(name) {
teacher = name;
//값이 변경됫는지 콘솔
console.log(teacher);
}
return (
<div className="App">
<button onClick={() => customSetTeacher('teacher!!!')}>영어로!</button>
<br />
<span>{teacher}</span>
</div>
);
}
export default App;
리랜더링이 발생하지 않는다..?
반드시 state 값을 'state변경함수'를 써야합니다.
customSetTeacher은 값은 변경이 되지만 > console.log에 변화있음
화면이 리랜더링 되지 않는다.
setTeacher 변경함수를 호출해야 React가 state 변경을 알아차리고 html을 변경해줌
onClick같은 것을 쓰게 되면 두가지 사용 방법
1. 익명함수 정의
2. 따로 함수 정의
* 익명 함수 정의 하지 않으면...
이렇게 쓰자!
함수 호출 방법
1. useState의 변경함수 setTeacher를 ㅡ> customSetTeacher() 함수 안에 넣는다.
2. 그 함수를 { 함수 } > () 안해도 된다!
실습1. 카운터 만들기!
•useState Hook 을 이용해서 간단한 카운터를 만들어 봅시다~!
•+ 버튼을 누르면 출력 되는 숫자에 +1 이 – 버튼을 누르면 -1 이 되도록 만들
어 주시면 됩니다!
•해당 카운터는 컴포넌트로 파일로 만드셔서 임포트 하시면 됩니다!
정답


import React, { useState } from 'react';
export default function Ex1() {
const [count, setCount] = useState(0);
return (
<div>
{count}
<br />
<button onClick={() => setCount(count - 1)}>-</button>
<button onClick={() => setCount(count + 1)}>+</button>
</div>
);
}
실습2 스위치, 컨디션 변경
스테이트를 변경하면 컴포넌트가 리랜더링되는데..
그럼 state가 변경될때 다른걸 변경(보여지는 요소가 바뀌면?)
3항 연산자를 사용해서 리액트스러운 뭔가 만들어봅시다.
삼항 연산자란
조건 (삼항) 연산자는 JavaScript에서 세 개의 피연산자를 받는 유일한 연산자입니다. 앞에서부터 조건문, 물음표(?), 조건문이 참(truthy)일 경우 실행할 표현식, 콜론(:), 조건문이 거짓(falsy)일 경우 실행할 표현식이 배치됩니다. 해당 연산자는 if...else문의 대체재로 빈번히 사용됩니다.
if...else - JavaScript | MDN
if 문은 지정한 조건이 참인 경우 명령문(statement)을 실행합니다. 조건이 거짓인 경우 또 다른 명령문이 실행 될 수 있습니다.
developer.mozilla.org
즉
조건식 ? true : false
true면 앞값을 리턴 / flase면 뒷값을 리턴
풀이
내가 푼 풀이 첫번쨰..
오답임 ㅋㅋ
첫번째 ㅠ
import React, { useState } from 'react';
export default function ConditionCopy() {
const [condition, setCondition] = useState(true);
return (
<div>
<button onClick={condition ? '😘' : '🤕'}>{condition}</button>
</div>
);
}
두번쨰
import React, { useState } from 'react';
export default function ConditionCopy() {
const [condition, setCondition] = useState(true);
return (
<div>
{condition}
<br />
<button onClick={() => setCondition(condition ? '😘' : '🤕')}>
컨디션 전환!
</button>
</div>
);
}
>> 음... true만 먹어서😘 얘만 나오네
true, false를 사용할거고 스위칭 시킬거면, not 논리 연산자를 썼어야 했다.
참은 거짓으로, 거짓은 참으로 not 연산자: !
1 . 익명 함수로 변경함수를 걸고 변경값에 ( ! condition ) > 참은 거짓 거짓은 참으로 변환 회로 넣고
2 . 출력되는 곳에 삼항 연산자를 쓰는 것임 > condition ? 참 : 거짓
import React, { useState } from 'react';
export default function ConditionCopy() {
const [condition, setCondition] = useState(true);
return (
<div>
{condition ? '😘' : '🤕'}
<br />
<button onClick={() => setCondition(!condition)}>컨디션 전환!</button>
</div>
);
}
선생님 정답

선생님은 style값도 주셧넹
실습3 좋아요 버튼 클릭시 아래의 숫자가 +1 컴포넌트 만든다.
숫자가 10이 넘으면 이모지를 변경 해주세요
위에서 개념을 익히고 나니
덜 해맸다..
버튼으로 회로를 잡고
출력에는 보여줄 삼항 연산자를 쓰면 된다.
import React, { useState } from 'react';
export default function GoodBtn() {
const [goodBtn, setGoodBtn] = useState(0);
return (
<div>
<button onClick={() => setGoodBtn(goodBtn + 1)}>{goodBtn}</button>
<br />
<span>{goodBtn < 10 ? '💓' : '💗'}</span>
</div>
);
}
이젠 안쓰지만
클래스형 컴포넌트의 state !
- 클래스형 컴포넌트는 Component라는 클래스를 상속하여 사용 ㅡ> Component 를 임포트 해야 합니다
- 클래스에서 사용하는 생성자에 state값을 지정합니다.
- this.state 라는 객체에 변경하고자 하는 값을 저장
setState xxxxxxx
> 단, state는 반드시 객체로 지정해서 사용해야 함!!!
- 그리고 this.setState 메소드를 이용하여 this.state 라는 객체에 저장 된 값을 변경합니다.
- State 변경이 일어나면 컴포넌트는 알아서 다시 랜더링 됩니다.
extends 상속
선생님이 상속이란 표현을 썼는데 extends 를 의미하는 것 같은데
부모의 모든 속성, 메서드를 상속 받는 것
이것은 단 하나의 class만 상속이 가능하며 그 기능을 쓸 수 있다고 하는 것 같다.
선언할땐
구조분해 할당
const { teacher } = this.state ;
불러올땐
this.setSate( { 키 : 값 } )
현재식으로 바꿔보면
위와 다르게
선언하는 부분
생성자 없고, state = { } 객체에 값을 넣었으며
render에 구조 분해할당으로 넣었다.
불러오는 부분
this.setSate( { 키 : 값 } )
state와 변수!
그럼 state와 변수를 한번 비교해 보자
**선생님 pdf파일 자료대로 하면 틀림!!
이 오류는.. eslint오류인데
자꾸 오류가 너 이거 상수인데 왜자꾸 재할당해라고 한다.
() 괄호 빼고
= 를 인식해서 안됬다 재할당 한다고 생각했나봐 ㅠ
하여간 코드를 완성해서
import React, { useState } from 'react';
export default function StateAndVariable() {
const [state, setState] = useState(0);
// console.log(state);
// 변수는 값이 변해서 let
// 변수인 variable은 뭐든 리랜더링하면 값이 0 으로 다시 초기화된다. 1을 최대값으로 가질 수 밖에 없다.
// 하지만 state는 컴포넌트가 다시 랜더링이 되어도 이전값을 기억하고 있다.
let variable = 0;
function setVariable() {
// 실행되는 시점이 온클릭 시점이라.. 0일수밖에!
variable += 1;
console.log(`state: ${state} / variable: ${variable}`);
}
return (
<div>
{state} / {variable}
<br />
{/* 두가지를 한번에 보여줘야 하니 중괄호 열기 */}
<button
onClick={() => {
setState(state + 1);
setVariable();
}}
>
+1
</button>
</div>
);
}
이렇다.
state는 값이 변경되지만, 변수는 값이 변경되지 않는다.
변수는 왜 계속 1인가?
state 가 변경되면 해당 state를 정의한 컴포넌트(함수)가 다시 리랜더링 된다
=> 함수가 다시 읽혀지면? 변수는 그 떄 다시 정의가 되어 계속 1이 된다.
State 사용시 주의 사항 !!!
자바스크립트의 자료형은
원시타입, 객체타입이 있다.
https://codingnewbie.tistory.com/43 내 정리글 참조
원시타입 로케이션이라는 메모리 주소 안에 korea 값이 들어가있음
객체타입 로케이션 메모리의 시작 주소값 > 그 주소로 가야 { county : korea }값이 있다.
원시타입은 주소 + 값이 같아서 true
객체타입은 내용 값은 동일하지만, 메모리 주소가 다르다.
다른 주소값이 나오기 때문에 같지 않다.
이렇기 때문에
import React, { useState } from 'react';
export default function ObjectStateCopy() {
const [obj, setObj] = useState([0]);
return (
<div>
{obj}
<br />
<button
onClick={() => {
obj[0] = 1;
setObj(obj);
console.log(obj);
}}
>
+1
</button>
</div>
);
}
초기값이 [0]값을 줫는데
배열이 시작되는 메모리 주소값을 가지고 있다.
밑에서는 주소를 변경한게 아닌 값을 변경했기때문에
state[0] = 1;
시작 주소가 같다.
리액트는 기존 state값과 / 새로운 state값을 비교할텐데
어떤값을 비교하게 되냐면
" 메모리 주소값을 비교 " 하기때문에 랜더링을 안하게 됩니다.
즉, state에다가 객체, 배열을 사용하면 js 특성상 랜더링이 안될겁니다
그럼 변경시키려면?
1. 새로운 주소값을 변경함수에 ..
import React, { useState } from 'react';
export default function ObjectStateCopy() {
const [obj, setObj] = useState([0]);
return (
<div>
{obj}
<br />
<button
onClick={() => {
setObj([1]);
}}
>
+1
</button>
</div>
);
}
[0] 배열
[1] 새로운 메모리에 값을 줌
[0] [1] 은 주소값이 다르다.
새로운 값을 넣는 방식으로 해줘야......! 값이 변경되는 그런일이...ㅠ
위에는 새로 만들었다
224페이지
2. 전개연산자
아래는 전개연산자를 이용해 배열을 만들어주는데
state 가지고있는 내부 값들이 들어가는데
값들은 동일하나
주소값은 새로 생기기때문에
뷰에는 값이 변경되어 보일것
잘못된 예
import React, { useState } from 'react';
export default function ObjectState() {
const [state, setState] = useState({ teacher: '이효석' });
console.log(state);
// const { teacher } = state;
return (
<div>
<button
onClick={() => {
state.teacher = 'tetz';
setState(state);
console.log(state);
}}
>
영어로!
</button>
<br />
{/* <span>{teacher}</span> */}
<span>{state.teacher}</span>
</div>
);
}
바꾼 예
주소값
새로 선언 해주기
1.
import React, { useState } from 'react';
export default function ObjectState() {
const [state, setState] = useState({ teacher: '이효석' });
console.log(state);
return (
<div>
<button
onClick={() => {
// state.teacher = 'tetz';
setState({ teacher: 'tetz' });
console.log(state);
}}
>
영어로!
</button>
<br />
<span>{state.teacher}</span>
</div>
);
}
2. 전개 연산자
import React, { useState } from 'react';
export default function ObjectState() {
const [state, setState] = useState({ teacher: '이효석' });
console.log(state);
return (
<div>
<button
onClick={() => {
// 값만 카피, 주소 변동
state.teacher = 'tetz';
const copyObj = { ...state };
setState(copyObj);
console.log(state);
}}
>
영어로!
</button>
<br />
<span>{state.teacher}</span>
</div>
);
}
결론
자주 값이 변경되고, 변경 사항을 바로바로 보여줘야 하면 state 선언 쓰기
배열 객체로 쓰기보다는 하나의 원시 값으로 쓰는게 좋다
배열 또는 객체를 사용해야 한다면, js 의 객체 타입 데이터 특성을 잘 생각해서 쓰자
초기값이 원시타입이면 상관없다
들어있는 값이 아닌 메모리 주소를 비교한다는 사실을 기억합시다~~~
컴포넌트 다시 랜더링하려면 상태변경함수로 값을 변경해야하만 컴포넌트가 리랜더링
리랜더링 조건은 state와 변경 state값이 달라야한다
/ㄴㅇㄴㅁㅇ
전개 연산자란
배열을 깨뜨리고 값을 뿌려주는 역할을 한다.
수업 요약
변경함수 써야 변경됨
익명함수 반드시 온클릭에!
해당 컨디션값에 따라 삼항 답이 바뀌는.....
state와 변수
변수는 변하지 않는다.
그 이유는
state는 컴포넌트가 리랜더링되어도 값을 보존하지만
변수는 리랜더링되어도 다시 재정의가 되어 값이 변하지 않는다.
값을 변화시킬거라면 변수가아닌 state에 넣어야 한다.
state 주의사항
초기값으로 배열, 객체를 사용할 시 문제가 생긴다.
state의 작동원리는 이전, 이후의 state값이 다르면 리랜더링 하는데
배열 객체로 하면 컴포넌트가 리랜더링이 안됩니다.
이 이유는 js적 원시타입, 객체타입의 다른점 때문이다.
원시타입은 바로 값이 있지만
객체는 메모리주소가 들어가 있다.
메모리 주소가 다르지 않는이상 js는 두개의 객체가 같다고 생각하여 리랜더링 하지 않는다.
해결법은
배열을 새로운 주소로 넣기
전개연산자 값 카피, 새로운 주소
객체 새로운 객체 지정, 전개연산자로....
'강의 정리 > React JS' 카테고리의 다른 글
2023-01-10 (0) | 2023.01.10 |
---|---|
2023-01-07 props (0) | 2023.01.07 |
2023-01-05 React prettier, eslint 설치 사용추천 (0) | 2023.01.05 |
2023-01-03 JSX 문법 (0) | 2023.01.03 |
2023-01-03 코테의 중요성과 하면 좋은 것 + React 강의 추천 (0) | 2023.01.03 |