다음은 "Next"
버튼을 눌렀을 때 다음 이미지를 불러오고 그에 따른 이미지 번호를 표시하는 Gallery
component이다.
import { sculptureList } from './data.js';
export default function Gallery() {
let index = 0;
function handleClick() {
index = index + 1;
}
let sculpture = sculptureList[index];
return (
<>
<button onClick={handleClick}>
Next
</button>
<h3>
({index + 1} of {sculptureList.length})
</h3>
<img src={sculpture.url} />
</>
);
}
handleClick
이라는 event handler function을 통해, 버튼이 클릭될 때마다 index
를 1씩 증가시키고 이에 따라 다른 이미지와 텍스트를 출력한다.
그러나, 제목에서 알 수 있듯, Gallery
component는 정상적으로 작동하지 않는다. 이는 handleClick
이 local variable을 수정하기 때문으로, 크게 다음 두 가지 이유가 올바른 동작을 막는다.
Local variables don't persist between renders - 초기에 언급했듯이 component는 결국 JavaScript function으로 render는 곧 해당 function의 실행을 의미한다. 당연하게도 실행 과정에서 local variable은 초기화된다.
Changes to local variables won't trigger renders - React의 입장에서는 local variable의 변경을 알아차릴 수 없다. 결과적으로 다시 render할 시점을 React에서 알아차릴 수 없다.
따라서 위의 두 문제를 해결하기 위해 다음 특성을 갖는 새로운 형태의 변수 혹은 데이터를 만들어야 한다.
Retain the data between renders
Trigger React to render the component with new data (re-rendering)
이를 위해 React는 useState
함수를 제공하며 이 함수는 다음 두 값을 제공한다.
State variable - retains data between renders
State setter function - update the variable and trigger re-rendering
두 값은 하나의 배열로 묶어 반환되며 const [index, setIndex] = useState(0);
와 같이 사용 될 수 있다.
useState
를 이용하여 수정한 Gallery
component는 아래와 같다.
import { useState } from 'react';
import { sculptureList } from './data.js';
export default function Gallery() {
const [index, setIndex] = useState(0);
function handleClick() {
setIndex(index + 1);
}
let sculpture = sculptureList[index];
return (
<>
<button onClick={handleClick}>
Next
</button>
<h3>
({index + 1} of {sculptureList.length})
</h3>
<img src={sculpture.url} />
</>
);
}
기존에 사용하던 local variable index
가 state varialbe로, 이에 대한 수정은 state setter function인 setIndex
로 수정되었음을 주목하자.
• Anatomy of useState
💡 When you call
useState
, you are telling React that you want this component to remember something
앞서 말했듯이, local variable의 경우 render마다 초기화 되며, React는 해당 variable의 변화를 알아차릴 수 없다. 따라서, useState
를 통해 특정 변수를 component가 계속 기억하고 모니터링하도록 React에 요청한다.
const [index, setIndex] = useState(0);
useState
는 state variable의 초기값을 인자로 받는다. 따라서 state variable index
의 초기값은 0
이다.
또한 naming convention에 따라 state variable과 setter function은 [something, setSomething]
의 형태로 명명한다.
• Meet your first Hook
React에서 useState
와 같이 use
로 시작하는 함수를 Hook이라고 칭한다.
💡 Hooks are special functions that are only available while React is rendering. They let you “hook into” different React features.
🚨 Hook은 component의 최상위 레벨에서만 사용이 가능하다. 다시 말해, 반복문이나 조건문 내에서 사용 불가하다.
다음은 위의 Gallery
component를 두번 render한 Page
component이다.
import Gallery from './Gallery.js';
export default function Page() {
return (
<div className="Page">
<Gallery />
<Gallery />
</div>
);
}
두 Gallery
component 내의 state는 독립적으로 존재하므로 하나의 버튼을 누른다고 해도 나머지 하나의 사진과 텍스트는 변하지 않는다.
주목해야 할 점은 크게 두 가지이다.
💡 State is local to a component instance on the screen
먼저, state는 함수 호출이나 코드가 아닌 화면에 종속된다. 위의 예시에서도 useState()
는 단순히 Gallery
component 내에 코드로써 작성되어 있지만, 각 각의 화면에 종속된다.
💡 Unlike props, state is fully private to the component declaring it.
또한, Page
component는 state에 대해 아무런 정보를 갖지 못한다. prop과 달리 state는 온전히 component에 종속되며 parent component는 state에 변화를 줄 수 없다.