✔️ React 의 useState

Wiiiiiii·2022년 9월 27일
0

Reactstudy

목록 보기
1/5
post-thumbnail

리액트에서 변수를 만들어 사용하려면 어떻게 해야할까?

let ret1 = 10;
var ret2 = "Hello";

위와 같은 선언자들로 변수를 생성한 후 리터럴을 대입해주어 변수를 생성하고 불러다 사용할 수 있다

하지만 리액트에서는 재랜더링이라는 과정을 위해 변수의 직접적인 생성 보다는 State 라는 자료형을 활용하여 변수를 활용한다

그렇다면 State를 왜 사용하여야 하는지 궁금하지 않은가!

예시

import {useState} from 'react'; >> state 임포트

function App () {
	let post = "포스트 제목"; >> 일반 변수

	return (
	<div className="App">
		<div>
			<h4>{post}</h4> 
		</div>
	</div>
)
}

위 코드에서는 post라는 일반 변수를 선언하여 리액트 App 컴포넌트 내 HTML 태그에 사용하였다
그런데, 이렇게 코딩했을때 post의 정보가 갑자기 변경되었다고 가정하면 새로운 정보가 바로 적용이 될까?

아마도.. HTML을 다시 로드해주어야 새로운 정보가 반영된 post가 표시될 것이다

이 번거로운 과정을 없애고 '웹앱' 의 구조 (재랜더링) 를 실현하기 위해서 사용되는 것이 바로 state 자료형이다!

let[a,b] = useState('포스트 제목');

State를 선언하려면 배열을 먼저 적어주고 배열의 인자로 [state이름, state변경함수] 를 적어주어야 한다
그리고 리터럴에는 useState(); 함수를 대입시켜주면 State 를 하나 만들 수 있다!

근데 왜 배열로 리터럴 값을 대입받습니까?

State의 정보를 변경하려면 State를 직접 수정하지 않고 State 변경함수를 사용해주어야 하기 때문이다

🔥 State를 직빵으로 바꾸려고 a = "10"; 을 적었다면 파싱에러가 당신을 맞이해줄 것이다

그래서 useState(); 가 담고있는 정보는 State의 값 + State변경함수 이며, 두 가지 정보를 대입받기 위해 Array Distructuring 을 사용한 것이라 이해하면 될 것이다

만약 ret 이라는 State에 "Hello world" 라는 문자열이 담겨 있는데, 이를 "Bye world" 로 바꾸어 주고 싶다면?

let [ret,setRet] = useState("Hello world"); -> 1. 선언
setRet("Bye world"); -> 2. 변경

State 변경함수의 파라미터로 바꾸어 줄 State정보를 넣어주면 된다!

❗️ Object, Array 형식의 State 변경 시 유의사항

오브젝트나 배열자료형의 경우 State변경 함수를 이용할 때 다음과 같이 이용할 수도 있다

let [a,b] = useState(["first","Second","Third"]);
...
<span onClick={ ()=>{ b(["One","Two","Three"]); } }>...</span>

하지만 오브젝트나 배열자료형은 원본을 보존하면서 특정 자료만 변경해주는 것을 권장하고 있다

let [a,b] = useState(["first","Second","Third"]);
...
<span onClick={ ()=>{ b(

	let copy = a; => 에러 발생
	copy[0] = "One";
	b(copy);

); } }>...</span>

배열정보를 담고 있는 a 라고하는 State를 copy라는 변수에 바로 할당하게 되면 정상적으로 State 변경이 이루어지지않는다

  1. State 변경함수의 특징
    State변경함수(새로운리터럴) ➡️ 새로운 리터럴로 State를 갈아치워준다
    ❗️조건 : 기존 State와 새로 바꿔줄 State를 등호로 비교하여 만약 기존 State == 신규 State 라면 변경을 수행하지 않는다
  1. Javascript 에서 Object, Array 자료의 특징
    배열과 오브젝트 자료의 경우 아래와 같이 생성했을 경우 로직은 다음과 같다
    let arr1 = [1, 2, 3];
    arr1 이라는 변수에 [1, 2, 3] 이라는 배열정보를 저장하는 것이 아니다!
    자바스크립트는 새로 생성된 배열 정보를 미지의 메모리공간에 저장해놓고 그 메모리 공간을 가리키는 '화살표' 정보를 arr1에 할당하는 것이다(포인터)
    실제 배열 정보는 RAM 안에 기억공간에 저장되게 된다
let [a,b] = useState(["first","Second","Third"]);
...
<span onClick={ ()=>{ b(

	let copy = a; => ERROR!
	copy[0] = "One";
	b(copy);

); } }>...</span>

위 코드를 다시 해석해보면 copy라고 하는 변수에 a 라고 하는 실제 배열정보를 가리키고있는 포인터 값을 할당한 후, 이 참조하고 있는 메모리공간 상의 배열정보의 첫 번째 인덱스를 "One" 이라고 하는 문자 리터럴로 변경한 후 해당 정보로 State 변경해주세요~ 라는 의미이다

그러나 a 가 가지고 있던 해당 배열정보의 포인터 값과 copy가 a 로부터 복사한 포인터 값이 동일한 상태에서 state변경을 진행하게 되면 컴파일러가 기존 state == 신규 state 라고 해석하여 정상적으로 변경을 수행할 수 없는 것이다

실제로 콘솔에 console.log(copy == a); 로 출력해보면 항상 true로 출력된다..

그렇다면 어떻게 바꾸어 주어야 할까?

❗️Spread Operator 를 사용하면 원본 정보를 보존한 채 새로운 배열을 생성하여 처리할 수 있게 된다

let [a,b] = useState(["first","Second","Third"]);
...
<span onClick={ ()=>{ b(

	let copy = [...a]; => "GOOD!"
	copy[0] = "One";
	b(copy);

); } }>...</span>

[...a] 의 의미는 a 가 가지고 있던 배열정보의 괄호를 벗겨주신 다음에 다시 새로 씌워주십쇼 이다
그렇게 되면 기존 a 와는 완전히 독립적인 배열의 사본이 만들어지게 되고 copy 가 가지고 있는 메모리공간 포인터 정보와 a 의 포인터 정보가 달라지게 된다

따라서 컴파일러는 기존 state != 신규 state 라고 인식하여 State 변경을 수행하게 된다

profile
리액트를 주로 연구중입니다! FE Junior

0개의 댓글