이번 시간에는 사용자 경험을 개선해 보겠습니다
일단 요청을 보내는 부분입니다
이 작업을 위해서는 커스텀 훅을 만들어야 합니다
그 이유는 컴포넌트가 두 개이기 때문입니다
즉 결제 컴포넌트와 음식 컴포넌트인데
이 컴포넌트 둘 다 요청을 보내야 하되
요청을 보내는 시점이 각각 다릅니다
둘 다 요청을 보내기는 합니다
그리고 두 컴포넌트 모두 다양한
요청 상태를 받아야 하는데
요청 실패, 요청 로딩 중
그리고 성공한 요청 상태입니다
그러므로 같은 로직을 쓰되
두 개의 다른 컴포넌트에 써서 UI를 업데이트해야 합니다
그리고 상태 유지 로직이
UI에 영향을 주기도 하고 변화가
UI에 영향을 주기도 해야 하므로 커스텀 훅이 필요합니다
단순히 커스텀 표준 함수만으로는
이 작업이 불가능합니다
그러므로 소스 폴더(src)에 훅 폴더(hooks)를 만들고
이름을 useHttp로 하겠습니다
이 이름을 가진 파일에서 먼저는
useHttp라는 함수를 내보내겠습니다
그리고 이미 배우셨듯이
커스텀 훅은 언제나 use로 시작되어야 합니다
이렇게 해야 리액트가 특수한 규칙을
이 훅에 적용할 수 있기 때문입니다
이 커스텀 훅 함수 안에
http 요청을 보내야 합니다
물론 이미 언급한 대로
훅을 포함한 컴포넌트를
렌더링하는 바로 그 순간에
요청을 보내서는 안 됩니다
음식 컴포넌트에서는 그래도 되지만
결제 컴포넌트에서는 그러면 안 됩니다
이 요청은 수요가 있을 때에 보내는 것인데
예를 들면 handleSubmit 함수가 실행될 때입니다
그러므로 먼저는
여기에 다른 함수를 더하겠습니다
위치는 useHttp 파일이고, 이름은
sendHttpRequest로 하겠습니다
실용성을 위한 함수인데
http 요청을 보내는 로직 일반을 감싸게 됩니다
비동기(async) 함수로 URL 및
구성 객체를 받는데, 예를 들면 fetch입니다
이 안에서는 fetch를 감싸고
URL을 fetch와 구성 객체에 보낼 것입니다
간단한 작업입니다
그러면 응답을 받을 수 있게 되는 시점이
바로 URL이 fetch로 전송되길 기다릴(await) 때입니다
이 부분은 문제가 생길 수도 있는데
백엔드에 오류가 생기면 응답에 문제가 생길 수 있습니다
이 경우에는 에러를 하나 사용하겠습니다
여기서는 내장 에러 생성자 함수를 만들겠습니다
브라우저가 제공하는 함수입니다
즉 이 에러는 메시지를 하나 가져오게 되고
메시지는 직접 입력하겠습니다
'문제가 생겼습니다. 요청을 보내지 못했습니다.'
굉장히 포괄적인 내용입니다
더 구체적으로 만들기 위해서
응답에 문제가 없는지 보기 전에 다른 검사를 하겠습니다
바로 응답 데이터를 확인하는 것입니다
응답에 에러 코드가 있다고 해도
여전히 데이터가 있을 수 있습니다
그 이유는 백엔드에서
이 코드를 살펴보면
에러 응답을 반환할 경우
그러니까 주문 경로에 데이터가 누락될 경우에도
응답 데이터 객체를 포함한
응답을 반환하게 됩니다
이 경우에는 메시지 속성이 있는 객체가
더 구체적인 에러 메시지를 내보냅니다
이 경우는 데이터가 잘못 입력되었을 때입니다
그러므로 이 데이터를 추출하겠습니다
바로 await response.json을 호출하면 됩니다
그리고 여기에 에러를 보낼 때
응답 데이터를 확인해서
메시지 속성이 있는지 확인할 수 있습니다
만약 이 경우라면 이 메시지를 사용하고
다른 경우에 대체하기 위해서는
좀더 포괄적인 에러 메시지를 사용합니다
이 if 검사를 통과한 경우라면
오류가 없는 경우이므로
응답 데이터를 헬퍼 함수에 반환하면 됩니다
이제 훅으로 다시 돌아가 보겠습니다
이 헬퍼 함수를 여기에도 사용할 것이기 때문입니다
그 이유는 이 useHttp에 있는데
여기에 커스텀 훅 함수에 포함된 다른 함수를 추가하겠습니다
함수 이름은 sendRequest로 하겠습니다
위에 있는 다른 헬퍼 함수와 비슷하지만
이 헬퍼 함수의 의의는
요청을 보내는 업무 전반을 담당하는 것입니다
아래쪽의 훅에 있는 이 함수는 이제
요청 상태에 따라 상태를 업데이트하게 되므로
이름을 sendRequest로 짓겠습니다
이 함수 바디에서 sendHttpRequest를 호출하면
위에서 정의한 다른 헬퍼 함수를
커스텀 훅에 있는 SendRequest에서 사용하게 됩니다
sendRequest는 비동기 함수가 될 수도 있습니다
커스텀 훅에서는 이렇게도 가능합니다
이렇게 해도 문제가 없습니다
여기에서는 물론 응답 데이터를 받겠지만
윗쪽의 커스텀 유용성 헬퍼 함수가 반환하는 것도
동일하기 때문입니다
이제는 이 내용을 try와 catch로 감싸겠습니다
이 부분에도 오류가 생길 수 있기 때문입니다
예를 들어 sendHttepRequest에서는
에러 응답 코드를 받으면 에러 메시지를 보냈습니다
그리고 예를 들어 요청을 보내는 과정에서
오류가 생겨도 오류 메시지를 받습니다
인터넷 연결이 안 되어 있다거나
하는 경우의 이야기입니다
그러므로 이것을 여기에도 적용해서
일어날 수 있는 오류에 대비하겠습니다
여기에서는 상태 제어를 통해서
UI의 다양한 요청 상태를 나타내야 합니다
이 커스텀 훅의 의의는 결국
컴포넌트 안에서 쓰기 위함이기 때문입니다
그러므로 여기에서 useState 훅을 사용해서
리액트에서 가져옴으로써
여기에서 에러 상태 제어가 가능하게 하겠습니다
이름은 error와 setError로 하겠습니다
초기에는 정의되지 않은 상태입니다
이 catch 블록에서 setError를 호출하고
error.message와 대응시키겠습니다
만약 오류가 생겼는데도
메시지가 없는 경우가 있을 수 있으니
여기에 대비책으로 메시지를 하나 만들겠습니다
'문제가 발생했습니다.'로 하겠습니다
이 메시지는 화면에 가급적 뜨지 않기를 바랍니다만
어쨌든 대비책으로 하나 만들어 두었습니다
이제 에러 상태와 더불어
성공한 사례에 대한 상태도 만들고
로딩 중인 상태도 필요한데
즉 응답을 기다리는 중의 상태입니다
그래서 useState를 다시 써서
isLoading 상태를 가지고 로딩 상태를 제어하겠습니다
setIsLoading 상태라는 상태 업데이트 함수도 사용하겠습니다
초기에는 값이 False인데
아직 로딩을 하지 않는 경우라고 볼 수 있습니다
그러나 sendRequest에서는 setIsLoading을
바로 호출해서 true로 설정하는 것이 좋습니다
곧 응답을 보낼 것이기 때문입니다
이 내용을 try와 catch 블록 이후에 false로 설정하겠습니다
오류가 있었든지 없었든지
이제는 로딩할 것이 없기 때문입니다
그리고 여기에 주요한 경우가 있는데
즉 백엔드에서 데이터를 가져왔을 때를
상태로서 제어하는 것입니다
이 경우는 성공의 사례라고 볼 수 있겠습니다
데이터를 가져온 후 이 try 블록에서
여기에 데이터 상태를 설정하겠습니다
커스텀 훅을 사용하는 의의는
이제 여기에 객체를 반환해서
데이터, 즉 isLoading 상태 및 에러 상태를
현재 커스텀 훅을 사용하고 있는 컴포넌트에
노출하게 됩니다
그러므로 이 훅을 쓰는 컴포넌트라면
이 함수에서 실행된 이 데이터, 즉 isLoading 상태와
이 에러 상태와 상태 변화로 인한 이점 모두
사용이 가능해집니다
이 함수를 좀더 살펴보겠습니다
현재 시점에서 이 함수는 단 한 번도 실행된 적이 없습니다
여기에 존재하지마 호출한 적은 없습니다
그 이유는 이 함수가 여러 위치에서
호출되어야 하기 때문입니다
이미 언급한 대로 결제 컴포넌트에서
이 함수는 이 위치에 호출되어야 합니다
이 handleSubmit의 fetch 호출 자리입니다
반면에 음식 컴포넌트로 가 보면
그 함수는 useEffect에서 호출되어야 합니다
간단한 해결방법이 있다면
sendRequest 또한 이렇게 노출하는 것입니다
그렇게 하면 이 훅을 사용하는 모든 컴포넌트가
필요할 때마다 sendRequest를 호출하게 됩니다
이것도 그렇게 나쁜 방식은 아닙니다만
이 커스텀 훅을 좀더 유용하게 하기 위해
여기에도 useEffect를 호출하겠습니다
물론 이 훅을 useState에서 먼저
불러와야 합니다
그리고 여기에서는 sendRequest를 호출하겠습니다
이렇게 sendRequest를 호출했습니다
sendRequest가 이 effect 함수의 의존성(dependency)이 되었습니다
이 요청 함수의 외부에서 정의되었기 때문입니다
그러므로 여기에 추가해야 합니다
그러므로 함수에서 상태 업데이트를 하면서
무한 루프에 빠질 수도 있는데
업데이트가 훅을 사용하는 컴포넌트로 하여금
재실행되도록 할 수 있기 때문입니다
이렇게 되면 이 effect 함수도 재실행됩니다
sendRequest는 주변 컴포넌트가 재실행 될 때마다
sendRequest의 내용이 변하게 되는데
이는 새 함수 객체가 생성되기 때문입니다
이 무한 루프에 빠지지 않기 위해
이 함수를 useCallback으로 감싸겠습니다
이 부분은 이전 강의에서 다룬 적이 있습니다
이 부분을 useCallback으로 감싸고
의존성 배열을 추가해서
여기에 send 요청 함수를 받겠습니다
useCallback에서 받아오는 것인데, 이제 이 내용은
의존성이 변할 때만 재생성됩니다
현재로서는 여기에 의존성이 없습니다
물론 엄밀히 말하면 다릅니다
이 sendRequest 함수 안에
sendHttpRequest로 데이터를 보내서
올바르게 구성해야 하기 때문입니다
그 이유는 sendHttpRequest는 적어도 URL이 필요하고
구성 객체까지 필요할 수 있기 때문입니다
그러므로 커스텀 훅은 URL과 더불어
구성 객체도 받아야 하는데, 즉
둘을 포함하는 requestConfig 객체를 받게 됩니다
이 부분은 임의로 설정하셔도 됩니다
저는 여기에서 매개변수를 두 개 만들어서
URL과 구성을 sendHttpRequest로 보내겠습니다
이제는 이 둘을 의존성으로서 useCallback에 추가하겠습니다
그 이유는 이 둘 중 하나라도 변한다면
새로운 함수 객체를 만들어야 하기 때문입니다
이 안의 코드가 변하기 때문입니다
사실 sendHttpRequest는 다른 데이터로
호출되어야 합니다
이제 여기에 있는 sendRequest를 useEffect에서 사용할 수 있고
이 훅을 사용하는 컴포넌트가 로딩될 때마다
이 요청을 보내게 됩니다
음식 컴포넌트에는 이 작업을 하는 것이 맞지만
결제 컴포넌트에 동일하게 적용할 수는 없을 것입니다
그러므로 커스텀 훅에 있는 이 effect 함수에서
검사를 몇 번 추가해서
send 요청이 보내지지 않는 경우가 있는지 확인하겠습니다
여기에 추가할 수 있는 검사내용은
이 구성 객체를 보는 것인데
이 객체는 커스텀 훅의 입력값으로 가져오는 것이므로
여기에 사용되는 요청 메소드를 확인해야 합니다
만약 그 메소드가 GET이거나 구성 객체가
애초에 제공되지 않았었다면
그 경우에는 요청을 바로 보내야 합니다
이 앱에서는 각 GET 요청이
보내져야 하는 시점은
이 훅을 포함하는 컴포넌트가 렌더링될 때입니다
만약 요청 메소드가 다르다면
요청을 보내지 않게 하겠습니다
이 구성의 True 혹은 False값을 확인하고
설정이 되었는지 여부도 보겠습니다
만약 설정이 되었고 메소드가 GET과 같다면
sendRequest를 실행하겠습니다
다른 경우에는 아무 작업도 하지 않겠습니다
이제 구성을 더해야 하는데
여기에서 사용하고 있으므로 의존성으로 더해야 합니다
이제 이 작업을 통해서
이 요청을 보내는 시점이
GET 형식의 요청을 받을 때라는 것을 확인할 수 있습니다
다른 요청의 경우에는 여기에 sendRequest를 노출하되
커스텀 훅에 의해 반환된 객체 속에
넣음으로써 이 커스텀 훅을 사용하는
다른 컴포넌트들도 이 sendRequest 함수에
직접 접근하고 필요할 때에 직접
실행할 수 있게 하겠습니다
예를 들어 양식을 제출했을 때에
이제 음식 컴포넌트로 가서
useEffect를 모두 삭제하고
useState 코드도 삭제하고
이 입력값도 모두 지울 수 있습니다
그리고 대신 훅 폴더에서 useHttp를 가져오겠습니다
거기에 있는 useHttp.js 파일에서
useHttp를 호출할 수 있습니다
그리고 이제는 그 URL을 전달하면 됩니다
이 URL에는 요청이 첫 인자로 전달되고
구성 객체가 두 번째 인자로 전달됩니다
이것이 GET 요청이기 때문에
여기에는 구성 객체가 필요하지 않습니다
여기에서는 객체를 반환받는데
여기에 객체 구조 분해 할당을 사용해서
곧 반환될 데이터를 확보할 수 있습니다
즉 isLoading과 에러 상태입니다
그리고 이제 이 상태들을 음식 파일에서 사용할 수 있습니다
예를 들면 이 아랫쪽에서 반환되어야 하는 데이터입니다
이제 데이터가 결국에는
loadedMeals가 될 것임을 알기 때문에 별칭(alias)을 써서
이 코드가 계속 작동하도록 하겠습니다
그리고 로딩과 에러 상태는 조금 있다 작업하겠습니다
먼저는 작동하는지 여부를 확인하고
특히 무한 루프 없이 작동하는지를
확인하겠습니다
이대로 저장 후 새로고침을 해 보면
아무것도 보이지 않고, 콘솔을 열면
에러가 보입니다
에러의 내용은 '정의되지 않은 속성을 읽을 수 없음' 입니다
이 에러가 음식 컴포넌트의 맵(map) 호출 시에 떴으므로
여기에서 매핑이 실패한 것 같습니다
여기에 있는 데이터가 정의되지 않았다는 의미인데
이 에러의 원인은 언제나
요청 전송이 실패한 경우입니다
혹은 다른 이유일지도 모릅니다
요청을 보내는 작업은 언제나 시간이 필요합니다
즉 데이터가 초반에는 도달하지 않는다는 뜻입니다
그러므로 데이터의 useState는
초깃값이 없는 이 초기 데이터 상태를
정의하지 않습니다(undefined)
즉 loadedMeals의 초깃값은
요청이 완료될 때까지 정의되지 않은 상태이며
시간이 걸리는 작업이지만 컴포넌트 함수는
이 요청 작업이 끝날 때까지 기다려 주지 않습니다
대신 JSX 코드를 구문 분석하여
바로 HTML 코드로 변환하게 됩니다
이 경우 당연히 코드 실행이 실패하는데
그 이유는 방금 설명했듯이 loadedMeals가
초기에는 정의되지 않기 때문입니다
이 에러 메시지도 거기에서 오는 오류입니다
이 문제를 해결하기 위해서는 먼저
로딩 상태인지 확인해야 하고
만약 그렇다면 반환하는 내용이 달라져야 합니다
예를 들면 '메뉴 가져오는 중...'이라는 문단입니다
이 정도 작업만 해도 해결이 된다고 생각하실 수도 있지만
이 상태로 저장 후에 새로고침을 해 보면
여전히 동일한 에러가 뜹니다
이 오류의 이유는
커스텀 훅인 isLoading은 초기에 false이기 때문입니다
이 훅은 요청을 보내기 시작하면서 true가 되는데
그렇게 하려면 이 effect 함수를 실행해야 합니다
이 함수는 아시다시피 컴포넌트 렌더링 이후에나 실행되고
즉 이 컴포넌트가 처음 렌더링되는 시점에는
isLoading은 False로 설정된 상태이므로
이것이 아닌 여기 있는 코드를 반환합니다
이 방식은 아까 설명했듯이 오류가 있는 것입니다
물론 isLoading을 초기부터 true로 설정할 수 있지만
이렇게 하면 이후에 또다시 문제가 되는 것은
이 훅을 결제 컴포넌트에서 사용하려고 할 때입니다
그 때에는 로딩 상태에서 시작하지 않기 때문입니다
그러므로 더 나은 해결방식이 있다면
여기에서 세 번째 매개변수를 받을 수도 있습니다
이름은 initialData로 하겠습니다
즉 커스텀 훅의 데이터 상태에 대해 설정하고자 하는
말그대로 초기 데이터입니다
이렇게 하면 음식 컴포넌트로 넘어갈 수 있고
useHttep를 사용해서 빈 객체를 전달하여
구성할 수도 있고, 그 후에는 이 빈 음식 객체를
loadedMeals의 초기 데이터로 전달할 수 있습니다
이것이 이전에 가지고 있었던 내용이고
이렇게 하면 이 함수가 처음 렌더링할 때
여기에서 아무 항목도 반환하지 않으면서도
오류가 나지 않을 수 있습니다
다른 방식으로는 검사를 한 번 더 하는 것인데
데이터가 정의되었는지 여부를 확인하는 것입니다
이렇게 하면 대비책 메시지를 반환할 수 있습니다
'음식 메뉴를 찾지 못함' 등이 있겠습니다
이것도 또다른 해결방식이지만
저는 여기에서 첫 번째로 사용한 초기 데이터 방식을 써서
이 방식을 좀더 보여드리겠습니다
이대로 저장 후에 새로고침을 하면
드디어 에러가 뜨지 않습니다만
음식도 하나도 뜨지 않습니다
로딩 문구도 안 보이고, 메뉴도 없습니다
이 현상이 일어나는 이유는
네트워크 탭을 열고 새로고침을 해 보면 알 수 있습니다
여기에서 백엔드에서 음식 메뉴를 가져오는
요청을 찾을 수 없습니다
아직 작업할 내용이 좀 더 있다는 뜻입니다
로직은 있는데 이 요청이 제대로
보내지지 않는 것 같습니다
그 이유는 여기에서 확인하는 내용이
구성 객체가 설정되었는지 여부인데
만약 설정되었다면 GET 메소드를 썼는지 확인합니다
여기서의 문제는 여기서 설정을 하지만
빈 객체에 설정하고 있다는 점입니다
그러므로 조건의 일부는 충족하지만
조건의 다른 부분, GET 메소드 부분은 충족하지 않습니다
이 문제를 해결하는 방법은 단 하나입니다
빈 구성 객체에 작업을 하는 것인데
메소드가 객체로 설정되지 않았을 때
GET 요청을 설정하기 위해서는
or 오퍼레이터를 추가해서 config.method가 정의되지 않았는지를
이 앞에 느낌표를 추가함으로써 확인해볼 수 있습니다
즉 이 코드를 실행사면서 구성 객체가 있는지 확인하고
또 메소드가 GET으로 설정되었는지 확인하는데, 만약 메소드가 설정되지 않았다면
이 부분을 괄호로 묶어서
언제나 구성 객체를 확인하도록 하면
요청을 보내기 위해 필요한 두 선택지 중 하나를
충족하게 됩니다
이제 여기에는 또다른 조건이 있습니다
요청을 보내기 위해 확인해야 하는 조건입니다
만약 구성 객체가 없다면
보내는 것인데, 그 이유는 구석 객체가 없으면
표준 방식으로 진행하겠다는 의미이기도 하기 때문입니다
즉 GET 요청이 보내지는 것이고
그 요청이 보내지는 시점은
지연 없이 바로 보내집니다
그러므로 구성이 있는지 혹은
GET 메소드가 있는 구성이 있는지 혹은
메소드 설정이 안 됐는지 확인하는 이 과정을 통해
드디어 요청이 보내지게 됩니다
하지만 이 수정을 한 후에
새로고침을 해 보면
또다시 에러가 나 있습니다
하지만 이번에는 loadedMeals가 정의되지 않은 문제가 아니라
이 에러는 매핑이 안 되는
무언가에 대한 에러로 보입니다
이 때에는 음식 컴포넌트로 돌아가서
loadedMeals를 console.log하면
어떤 데이터가 해당 상태에 저장됐는지 볼 수 있습니다
이 부분을 더하고 콘솔을 열어서 새로고침을 하면
여기에서 처음에는 빈 배열로 시작하다가
그 다음부터는 프로미스(promise)입니다
즉 올바른 값이 아닙니다
프로미스가 아니라 음식 배열이어야 하기 때문입니다
왜 음식 배열 대신에 프로미스가 나올까요?
그 이유는 커스텀 훅에 있습니다
여기에서 sendRequest를 실행하고
이 훅은 sendRequest 안에 있고
이 함수에서 데이터를 설정합니다
여기에서 문제가 있는 줄은 여기입니다
데이터를 보내는 위치는 바로
sendHttpRequest 요청의 결과입니다
그러나 sendHttepRequest를 호출하면
곧 데이터를 받게 됩니다
즉 비동기 await을 사용하고 있으므로
sendHttpRequest는 프로미스 객체를 반환하는데
이 객체가 반환된 데이터로 가게 됩니다
즉 resData에 프로미스를 저장하는 것입니다
이 부분이 바로 문제입니다
해결방법은 여기에 await을 추가하는 것인데
비동기 방식을 사용하므로 이렇게 할 수 있습니다
이렇게 하면 가져오는 데이터를
resData에 저장한 후에 상태까지 이르게 됩니다
이제 이 문제도 모두 해결했으니
이제 새로고침을 해도 에러가 안 나올 것입니다
혹은 아까 설정해 둔 에러 메시지라도 뜰 것입니다
하지만 네트워크 탭을 다시 열어보면
다시금 좋지 않은 결과가 나옵니다
여기에 어떤 무한 루프가 만들어진 것 같습니다
여기에 요청이 아주 많이 생기고 있기 때문입니다
다행히 이 요청은 모두 가짜 백엔드에 저장되고 있긴 합니다만
왜 이런 일이 일어나는 것일까요?
이유는 바로 적어도 하나 이상의 의존성이, 즉
useEffect의 의존성이 계속 재생성되는데
커스텀 훅을 호출하는 컴포넌트가 재실행될때마다
의존성 또한 재생성되고 있는 것입니다
즉 sendRequest거나 구성의 문제입니다
이론적으로 sendRequest는
재생성될 수가 없습니다
useCallback으로 감싸 두었기 때문입니다
하지만 재생성될 수 있는 경우는
이것의 의존성이 계속 변할 때 입니다
여기에서는 URL과 구성이 있는데
음식 컴포넌트로 돌아가 보면
여기로 URL을 하나 보내고 있고
이 객체도 보내고 있습니다
그리고 초기 데이터도 보내고 있지만
중요한 부분은 이게 아닙니다
이것은 useCallback이나 useEffect의 의존성이 아니기 때문입니다
여기에 useHttep로 전달하는 구성 객체가 있습니다
바로 이 부분에 문제가 있습니다
여기에서는 큰 문제가 아닌 것 같지만
이것은 단순한 자바스크립트 객체로서
빈 객체지만 객체값은 여전히 있습니다
이 객체는 이 컴포넌트 함수에서 생성되고
그러므로 이 컴포넌트 함수에서 재생성되는 시점이
이 컴포넌트 함수가 실행될 때마다입니다
그리고 이 함수는 이 요청이 완료될 때마다 실행됩니다
그러므로 계속해서 재생성되는 객체입니다
해결방식은 이것을 이 컴포넌트 함수의
바깥에서 생성하는 것입니다
여기에서 requestConfig를 만들어
useHttp에 매개변수로 전달하겠습니다
아주 간단한 작업 같지만
이것으로 해야 할 작업이 모두 끝난 것입니다
이 파일이 처음 구문분석될 때
이 객체를 한 번만 생성하게 되므로
컴포넌트 함수 안에서도
저장된 동일한 객체를 사용하게 됩니다
이대로 저장 후 새로고침을 해 보면
이제 무한 루프가 없어졌고
드디어 음식 메뉴가 보입니다
작업할 내용도 많았고 에러도 많았습니다만
일부러 그 모든 과정을 하나하나 보여드렸습니다
그 이유는 리액트에 있어 부수 효과(side effect)나
Http 요청 작업 시에 오류가 날 수 있는 부분이
아주 많기 때문입니다
여러분들이 이런 문제를 해결하는 법과
자주 발생하는 에러의 원인을 알아두셨으면 좋겠습니다
이제 드디어 훅이 제대로 작동하는 것을 확인했으니
이제 앱 개발 작업을 재개할 수 있겠습니다
하지만 그 과정에서 여러분들은 요청을 보내는 작업, 리액트에서 문제를 해결하는 작업 그리고
부수 효과관련 작업을 상당히 많이 해냈습니다