이제 get 요청이 아닌
데이터도 보낼 수 있습니다
하지만 물론
어떻게 요청을 보내는지를 잘 살펴보면
주목해야 할 만한 것들이 몇 가지 있습니다
하나는, 제가 여기서 loading 상태를 관리하고 있지 않다는 것입니다
그리고 예전에 제가
이 세 가지 상태를 갖고
HTTP 요청을 보내는 게 흔한 일이라고 했습니다
그건 맞는 말이지만
이 앱 컴포넌트에서는
loading 상태를 관리하고
로딩 문구나 스피너를 사용자에게 보여주는 대신
낙관적 업데이트라는 것을 수행 중입니다
이 요청을 보내기 전에 local 상태를 업데이트합니다
응답을 기다리기 이전의 시점입니다
그래서 여기서 장소를 고르면
UI가 즉각 업데이트되고
뒤에서 요청이 동시에 보내졌다는 걸 알 수 있습니다
물론, 그 요청을 보내는 데에 실패할 수 있습니다
그래서 이 에러를 catch 할 때
제가 하고 싶은 건, userPlaces를 다시 지정해서
그 전의 상태로 재설정하는 겁니다
그러니까 결국 이전 userPlaces 상태입니다
이 함수 형식을 업데이트하는 데 사용하지 않습니다
여기에는 새로운 장소를 포함한
상태가 없기 때문입니다
하지만, 이 이전 userPlaces 상태를 사용하면
새로 선택한 장소는 포함되지 않고
뭔가 잘못됐을 때
변동사항을 복구시키고 UI를 다시 업데이트하면 됩니다
그리고 가끔 낙관적 업데이트는
사용자들에게 더 나은 경험을 제공합니다
로딩 문구나 스피너를 띄우는 것 보다 더 좋을 수 있습니다
물론 여러분의 선호도에 따라 달렸고
어떤 상황이냐에 따라 달라집니다
항상 가능한 것은 아니고 특히 데이터 fetching을 할 때
당연히 쓸 수 있으려면
기다려야 합니다
하지만 여기서 한 것처럼 업데이트를 할 땐
낙관전 업데이트가 좋은 방법일 수 있습니다
혹은, 이 코드를 여기로 옮겨서
장소를 업데이트해도 됩니다
바로 이 상태 업데이트 앞입니다
그러면 이 상태 업데이트는
요청이 끝날 때까지 기다립니다
하지만 그러려면
로딩 문구나 스피너를
띄워야 합니다, 그렇지 않으면
사용자에게는 앱이 멈춘 것처럼 보일 것입니다
그래서 저는 그렇게 하지 않고
이 코드를 주석 처리 하겠습니다
하지만 이 방법도 방법 중 한 가지가 될 수 있습니다
다시 한 번 말씀드리지만, 어떤 방법을 쓸지는 여러분께 달렸습니다
저는 여기서 낙관적 업데이트를 쓰기로 했습니다
하지만 그럼에도, 여기서 에러가 발생했고
이걸 사용자에게 알려줘야 할 필요는 있습니다
에러 전으로 복구 시키는 건 좋지만
사용자들에게는 아무 설명도 없이
작업한 내용이 사라지는 것이라
이렇게 하지 않아야 합니다
그래서 추가로 이 컴포넌트 안에
상태를 만들어보겠습니다
errorUpdatingPlaces 상태인데, 예를 들어
setErrorUpdatingPlaces= state를 업데이트하는 함수를 해주면
처음에는 아무런 값도 갖고 있지 않습니다
그리고 장소에 문제가 생겼을 때만 업데이트가 됩니다
그리고 이 catch 블록 안에는
변동사항을 복구하는 것 말고도
setErrorUpdatingPlaces를 불러서
객체에 상태를 설정하고
message 속성도 넣어줍니다
:error.message도 해주고 OR을 써서
대체 문구인 '장소 업데이트에 실패했습니다'도 써줍니다
이제 이 errorUpdating state를
화면에 에러 메시지를 띄우는데 사용할 수 있습니다
그리고 물론, 언제나처럼
에러 메시지를 띄우는 데는 여러가지 방법이 있습니다
그건 여러분에게 달렸지만
저는 이번에 모달(modal)을 띄워보도록 하겠습니다
Modal 컴포넌트로 모달을 추가하고
errorUpdatingPlaces가 True일 경우 열리게 하겠습니다
그러니까 에러가 발생했을 때만입니다
그러면 이제 error 컴포넌트를 보여드리겠습니다
전에 이미 공유한 내용입니다
이것도 당연히 가져오겠습니다
그리고 title은 '에러가 발생했습니다'로 지어줍니다
그리고message={errorUpdatingPlaces.message}입니다
물론 이 모달은
언제든 닫을 수 있어야 하고
언제든 에러 메시지를 지울 수 있어야 합니다
그러니 또 다른 함수를 추가해주겠습니다
이름은 handleError라고 지어주고 위치는 여기로 하겠습니다
setErrorUpdatingPlaces를 불러주고
다시 이걸 널(null)로 설정해줘서 에러를 없앨 수 있게 합니다
그리고 handlError는
onConfirm의 속성 값으로 사용할 수 있습니다
그러면 모달을 닫을 수 있게 됩니다
에러를 없앴기 때문에
모달의 onClose 속성에서도
모달이 닫히면 에러를 없애야 합니다
예를 들어 이 esc 버튼을 눌러서 말입니다
그리고 이 error 컴포넌트가
모달로 감싸져있는데
꼭 errorUpdatingPlaces가 Tru일 떄만 렌더링되어야 합니다
그렇지 않으면 이 메시지에 접근할 수 없기 때문입니다
비록 모달이 보일 때만 보이겠지만
바로 DOM의 일부가 될 것입니다
왜냐하면 modal 컴포넌트는
항상 DOM의 일부일 것이기 때문입니다
항상 열리는 것은 아니지만 항상 있는 겁니다
그러므로 항상
errorUpdatingPlaces.message에 접근하려고 시도해야 합니다
하지만 에러가 없을 땐 실패할 것이며
그래서 이 에러를 조건적으로 렌더링하는 것입니다
그럼 이제 새로 저장하고 새로고침을 하면
장소를 가져왔고 그걸 수정할 수 있습니다
하지만 제가 에러를 강제로 만들어 보겠습니다
예를 들어 또 다시 유효하지 않은 URL을 사용해보겠습니다
S를 여러개 더 추가하고 저장해보겠습니다
이제 아이템을 이렇게 클릭해 보면
이 에러 모달이 띄워진 게 보이고 닫을 수도 있습니다
그럼 다시 계속 진행하기 위해
이 에러를 없애겠습니다
그건 간단하게
이 S들만 지워주면 됩니다
여기까지 낙관적 업데이트와
어떻게 에러를 다뤄야 하는지 배워보았습니다