⚛️ useState는 await를 쓸 수 없다

헉 그럼 어떡해야 할까요?

YI Eun Gook
4 min readMay 1, 2019

음 사실 하고 싶은 말은 state를 state로 쓰지 말자 라는 말장난 입니다. 장난을 거두고 다시 말하자면.. state는 render를 위한 값으로 생각하고 사용하고, 어떤 상태state를 나타내는 데에는 가급적 쓰지 말자는 의견입니다.

어떤 UI로 예를 들어볼게요. 탭이 셋 있고, 버튼은 하나만 있습니다. 버튼을 누를 때 현재 활성화된 탭의 내용을 저장한다고 할게요. 탭은 render되어야 할 테니까 state가 필요할 것 같습니다. 대충 이런 느낌이 아닐까요?

const clickTab = i => this.setState({... state, tab: i, });
const clickSave = async () => await asyncSave(this.state.tab);

무리없이 동작할 것 같습니다. 그럼 여기서 각 탭을 누를 때마다 임시 저장을 한다고 해볼게요. 이런 느낌으로 짜보면 될까요?

const clickTab = async i => {
await this.setState({... state, tab: i, });
this.draft();
}
const draft = async () => await asyncDraft(this.state.tab);
const clickSave = async () => await asyncSave(this.state.tab);

마찬가지로 무리없이 동작할 것 같습니다. 하지만 이 구조를 react hooks로 바꿀 경우 의도대로 동작하지 않습니다.

async function clickTab(i) {
await setTab(i); // useState는 async-await를 지원하지 않습니다.
draft();
}
async function draft() {
await asyncDraft(tab); // tab != i
}
async function clickSave() {
await asyncSave(tab); // tab == i
}

clickTab()iclickSave()tab은 같을 것 입니다. 둘 모두 사용자의 액션으로 트리거되는 함수이기 때문에 setTab()으로 업데이트 될 시간이 충분히 있습니다. 하지만 draft()tab은 같지 않습니다. 아직 tab이 업데이트되지 않았기 때문입니다. 왜냐면 첫째로 tabstate이기 때문이고, 둘째로 useStateasync-await를 지원하지 않기 때문입니다. 그래서 이 코드는 의도대로 동작하지 않습니다.

하지만 아주 간단히 고칠 수 있습니다. 함수의 파라미터를 사용하면 됩니다.

function clickTab(i) {
setTab(i);
draft(i);
}
async function draft(tab) {
await asyncDraft(tab); // tab == i
}
async function clickSave() {
await asyncSave(tab); // tab == i
}

참 쉽죠?

setState는 promise를 반환하지 않습니다. 하지만 async-await를 통해 비동기로 동작합니다. (정확히는 비동기로 동작하는 것 처럼 보인다고 합니다만 저는 여기까지는 잘 모르므로 일단은 이렇게 표현해 두겠습니다. 😓)

즉 아까 같은 방식의 코드를 react 쪽도 이해하고 있었던 거겠죠. 하지만 useState훅은 그렇지 않습니다. 왜 굳이 지원하지 않는 걸까요? 라고 나름 생각해본 결과가 맨 처음 문장 이었습니다. state를 state로 쓰지 말자는 말장난이었어요.

state를 일종의 global variables로 써서는 안 된다는 거죠. (너무 다이렉트한 표현일까요 😱) 순수 함수를 목표로 함수의 동작에 영향을 주는 값.. 즉 상태state는 state가 아니라 함수의 인자값으로 넘겨주는게 좋을 것 같습니다.

가급적이요!ㅎㅎㅎㅎㅎ

--

--

No responses yet