- 스냅샷으로서의 state
- State 업데이트 큐
스냅샷
스냅샷이 무엇인가요?
→ 스냅샷은 말 그대로 ‘캡쳐화면’이라고 생각하시면 됩니다. react에서 상태는 마치 snapshot 처럼 동작하는데요, 이는 상태를 캡쳐해 놨다가, 상태를 변경하면 바로 반영되는 것이 아니라 리렌더링이 일어나면 값이 바뀌면서 캡쳐본이 바뀌는 형태라고 생각하시면 됩니다. 캡쳐화면도 화면이 바뀌어야 캡쳐가 바뀌잖아요!?
스냅샷으로서의 State
양방향 바인딩과 단방향 바인딩은 무엇이고, 어떤 차이가 있을까요 ?
→ 양방향 바인딩에서는 데이터가 변경되면 부모와 자식 컴포넌트 간에 서로 데이터를 주고받으며 영향을 주고받습니다. 반대로 단방향 바인딩은 반대로 데이터가 부모에서 자식으로만 흐르게 됩니다.
스냅샷은 단방향 바인딩에서 데이터의 상태를 이해하는 데 잘 맞는 개념입니다. React의 상태는 마치 특정 시점의 스냅샷처럼 작동하며, 상태가 변경되면 리렌더링을 통해 그 변경된 상태가 반영됩니다. 즉, 상태는 변경되더라도 단방향 바인딩이기 때문에 그 즉시 다른 모든 곳에 영향을 주는 것이 아니라, 리렌더링을 통해 새로운 상태가 UI가 적용되는 방식입니다.
따라서 단방향 바인딩에서는 상태가 변하면 데이터가 새로 업데이트된 컴포넌트로만 흐르고, 그 변화가 즉각적으로 외부 시스템에 반영되지 않습니다. 이런 이유로 useEffect가 필요한 것입니다. 상태가 변경된 후에 특정 외부 작업을 해야 한다면, 상태가 변경될 때 이를 감지하고 부수적인 작업을 실행하는 역할을 useEffect가 담당합니다.
또한 이렇게 단방향 바인딩을 이용하면 양방향 바인딩보다 애플리케이션의 예측 방향성을 높일 수 있습니다.
state는 실제로 함수 외부에 마치 선반에 있는 것처럼 React 자체에 “존재”합니다
여기서 말하는 '함수 외부'라는 게 위의 App.js를 예로 들면 Form( ) 외부를 말하는 건가요? state가 외부에 존재한다는게!! 1.일반적인 함수는 호출될 때 내부에서 변수를 만들고, 함수가 종료되면 그 변수들은 사라짐 한편, state는 컴포넌트 함수가 실행된 후에도 사라지지 않는다는 의미인가요?
→ 말 그대로 변수는 함수 내부에 있지만, ‘상태’는 리액트 자체에 있는 것이기 때문에 유지된다는 의미입니다. App.js도 함수라고 할 수 있고, 모두 다 함수입니다. 변수는 함수가 끝나면 사라지지만 state는 변수와 다르게 리액트 자체에 보관되고 있기 때문에 실행 후에도 계속 존재한다는 의미가 맞습니다~!
다시 렌더링하기 전에 최신 state를 읽고 싶다면 어떻게 해야 할까요? 다음 페이지에서 설명하는 state 갱신 함수를 사용하면 됩니다!
state 갱신 함수가 set함수를 말하는 걸까요 ?
→ 업데이터 함수를 말하는 것입니다~! n ⇒ n + 1 이런것..!! set함수는 렌더링 이후에 업데이트 됩니다.
과거에 생성된 이벤트 핸들러는 그것이 생성된 렌더링 시점의 state 값을 갖습니다.
그럼 이벤트 핸들러에서 최신값을 참조하고싶으면 useEffect 같은 훅을 사용하면 되는건가요? 최신값을 참조가 필요한 경우는 어떤경우가 있는지 궁금해요!
→ 이벤트 핸들러에서 최신값을 참조하고 싶다면 그냥 state를 가지고 set함수를 이용해서 사용하면 됩니다. 만약 그 값이 변할 때마다 이벤트를 일으키고 싶다면 useEffect와 같은 훅 함수를 사용해주면 됩니다.
업데이터 함수는 순수해야 하며 결과만 반환 해야 합니다. 업데이터 함수 내부에서 state를 변경하거나 다른 사이드 이팩트를 실행하려고 하지 마세요
이게 잘 와닿지가 않네요. 업데이트 함수 내부에서 state를 변경하는 건 앞에서 본 예시인 것 같은데, 다른 사이트 이펙트를 실행하는 건 어떤 걸 예시로 들 수 있죠?
→ 말 그대로 값을 반환하는 순수함수를 사용해라, 라는 의미입니다. 사이드 이펙트 예시가 있다면 console.log와 같은 프린트 함수가 가능할 것 같은데요, 예시 코드로는 아래와 같을 것 같습니다.
setNumber(n ⇒ {
const updatedNum = n + 1;
console.log(updatedValue);
return updatedNum;
});
챌린지 1 of 2: 요청 카운터를 고쳐보세요.
큐에 있는 값을 공용으로 쓰는 건가요? 저는 같은 큐 안에 있더라도 state가 다르면 영향을 줄 수 없다 생각했는데, 해설을 보니 큐 안에 있는 값을 pending도 쓰고 completed도 쓰는 것 같아서요..! 동작 과정 설명해주실 수 있으실까요🥲🥲
→ 독립적으로 쓰는것이 맞습니다!
여기서 handleClick 함수는 비동기적으로 실행됩니다. 이 함수가 실행될 때, setPending과 setCompleted가 큐에 넣어집니다. React에서 상태 업데이트는 일반적으로 큐에 쌓이게 되고, 컴포넌트가 리렌더링될 때 그 큐에 있는 업데이트들이 처리됩니다.
이 경우, setPending(pending => pending + 1)이나 setCompleted(completed => completed + 1)처럼 함수형 업데이트를 사용하면, React는 이전 상태 값을 기반으로 최신 값을 계산해 줍니다. 즉, 상태를 직접 참조하는 것이 아니라, 함수로 전달하여 최신 상태 값을 기반으로 값을 업데이트합니다. 이 방식으로 하면 비동기적으로 실행되는 상태 업데이트들 간의 충돌을 방지할 수 있습니다.
pending과 completed은 각각 별도의 상태지만, 동일한 렌더링 사이클 안에서 일어나는 것이기 때문에, 각 상태 업데이트가 큐에 쌓여 처리되는 과정에서 최신 상태를 참조하도록 되어있습니다. 따라서 pending의 업데이트가 먼저 큐에 쌓이고, await delay(3000)이 끝난 후에 다시 setPending과 setCompleted가 큐에 추가됩니다. 비록 각각의 상태 업데이트가 독립적이지만, 큐를 통해 순차적으로 처리되기 때문에 각 상태가 최신 값을 반영하면서 업데이트됩니다.
결론적으로, 같은 이벤트 핸들러 내에서 상태가 업데이트되기 때문에, 그리고 함수형 업데이트를 사용하기 때문에 큐에 쌓인 상태가 서로 영향을 줄 수 있는 것입니다.
챌린지 2 of 2: state 큐를 직접 구현해 보세요.
혹시 이 문제 해설 부탁드려도 될까욤.. update 함수가 어떤 동작을 하는지 정의되지 않았는데 어떻게 동작되고 있는지 이해가 잘 안됩니다..💦💦
→ 이건 업데이트 함수는 아니구, for문을 이용해 받은 queue 배열을 나눈 것입니다! 리스트 값이 함수면 함수로 동작, 값이라면 값으로 동작하게 구현해놓은 것이라고 생각하면 됩니다!
strict 모드로 개발시 api 중복 호출되는 문제가 생길수도 있다고 들은 것 같은데! 그럼 개발시에는 strict 모드를 지우고 하는것이 일반적인 방법인가요?
→ 만약 오류 체크를 더 잘 하고싶다면 지우지 않고 하면 됩니다! 이건 개발자의 자유입니다~