나름 세미나 1 과제보다는 쉽게 냈지만, 그래도 안 알려드린 부분이 많아 걱정하고 있었는데 다들 잘 해 주셔서 만족?스러웠던 과제였습니다! 배포 부분도 분명 처음 해 본다면 상당히 부담되는 내용인데, 잘 해결해주신 것 같습니다. 수고하셨어요!
공통 피드백 시작하겠습니다.
Context API의 사용
수업 시간에 설명드렸듯이 Context API는 Props Drilling을 하지 않아도 되게 해 주는 역할 딱 하나를 담당합니다. 또한 이를 응용한 Context best practice 코드는 데이터를 앱 전체에서 전역으로 사용할 수 있도록 도와줍니다. 따라서 불필요하고 더럽게 props를 넘기는 상황을 방지할 수 있습니다.
하지만 당연히 전역 데이터라는 것은 아주 조심스럽게 사용해야 합니다.
먼저 리액트의 특성상 성능 문제가 따릅니다. best practice대로면 Context Provider Component가 앱 최상단에 위치하기 때문에, 이 친구의 state가 변경되면 앱 전체가 리렌더됩니다. 즉 만약 검색어 인풋 텍스트를 state로 관리했다면, 키보드를 한 번 입력할 때마다 앱 전체 페이지가 리렌더되는 대참사가 일어나게 됩니다.
가독성 측면에서도, 전역 데이터가 불필요하게 많은 것은 좋지 않습니다. 전역 상태로 있어서 뭐 하는 친구인지 봤더니 필터 인풋 텍스트가 있다면, 다른 사람의 눈에는 이게 왜 여기 있는지 궁금해집니다. Context에 모든 state를 때려박는 것은 App.js에 모든 state를 때려박는 것과 마찬가지입니다. (사실 더 책임이 큽니다: App보다도 더 위에 있으니)
리팩토링할 때도 좋지 않습니다. 전역 데이터라는 것은 많은 곳에서 이 데이터를 사용하고 있을 수 있다는 가능성을 내포합니다. 때문에 전역으로 디자인된 그 코드를 나중에 고치고 싶을 때 부담이 많이 될 수 있습니다.
추가로, Context를 목적과 제공하는 값에 따라 잘 분류해야 합니다. 가령 학생 목록을 제공하는 Provider에 로그인 정보가 들어있는 것은 좋지 않습니다. 로그인 정보는 따로 AuthContext라든가 그런 곳에 있는 게 옳습니다. 물론 기능이나 성능상 차이는 없으나, 코드를 의미에 맞게 잘 분리하는 건 중요합니다. 한국말을 할 때 "나는 집에서 딸기를 먹고 학교에서 바나나를 먹었어"라고 하는 것과 "나는 딸기와 바나나를 집과 학교에서 각각 먹었어"라고 하는 것 중 전자가 훨씬 이해가 잘 됩니다. 이것과 유사한 이유라고 생각해주시면 됩니다.
제가 이 과제를 혼자 구현해봤을 때는 아래와 같이 디자인했습니다.
StudentDataContext: 학생 리스트 데이터, 학생 추가 함수, 학생 삭제 함수, 학생 수정 함수를 제공
AuthContext: 로그인되었는지, 로그인시키는 함수, 로그아웃시키는 함수
이외의 모든 상태를 각 컴포넌트의 state에 적합하게 집어넣어 구현하였습니다. 여담으로 당연히 과제 3도 미리 구현해 봤는데, 이때는 어차피 학생 추가나 삭제 등의 로직을 서버가 모두 담당하기 때문에 StudentDataContext가 딱히 필요가 없어졌습니다. 그래서 저는 로그인 정보 (AuthContext) 하나만 Context로 관리했습니다. 로그인 정보가 바뀌는 건 자주 있는 일도 아니고, 그 경우 앱 전체가 리렌더되는 건 너무 당연하니까요!
여기까지 읽으면 다음과 같은 의문이 들 수 있습니다.
그러면 Context는 거의 쓸 일 없겠네요?
뭐 일단 제 취향은 그렇습니다. 제가 개인적으로 / 회사에서 / 팀에서 프로젝트를 진행할 때 전역으로 저장하는 값은 대부분의 상황에서 로그인 정보 하나뿐입니다. (리덕스를 쓴다면 말이 다르지만요)
하지만, 꼭 Context를 적게 써야 한다고 단정지을 수는 없습니다. 전역으로 쓸 만한 값들이 많을 수도 있죠. 또한 페이지의 특성에 따라 best practice처럼 사용하지 않고, 그냥 컴포넌트 자체에서 바로 Context.Provider 불러서 provide할 경우도 있을 수 있습니다. 리액트는 언제나 자유로운 코드 문화를 가지고 있었기에 항상 "이렇다" 라고 말할 수 있는 건 거의 없습니다.
아무튼 중요한 건 본인의 앱이 어떻게 돌아가는지 확실하게 이해하는 거예요. Context에 많은 데이터를 넣을수록 성능에 부담이 된다 (너무 큰 규모의 많은 리렌더가 일어나니까)는 걸 이해하고 계신 게 중요합니다. 그리고 그걸 이해하고 계시다면, 적어도 이번 과제에서는 어느 정도의 props drilling을 감수하더라도 저와 같이 디자인하는 게 좋을 거란 의견에 동의하실 것 같네요!
로그인 정보 유지
로그인 정보 유지를 위해 localStorage를 사용하신 분들이 많았습니다. 잘 구현해 주셨더라고요 👍
하지만 일단 localStorage가 state보다 접근하는 데 더 오래 걸립니다. 또한 localStorage의 데이터는 mutable하므로 자주 접근하게 되면 리액트스럽지 않아집니다.
따라서 로그인 정보는 항상 state에 저장해 두고, localStorage는 정말 딱 "백업용"으로, 앱 켜질 때 / 로그인할 때 / 로그아웃할 때 말고는 한 번도 접근하지 않는 게 좋습니다. 가령 App.js에서 localStorage.getItem()하여 로그인 상태를 확인하는 등은 바람직하지 않겠군요
기타
camelCasePascalCase 제발 지켜주시길 간곡히 부탁드립니다..
515 참고하셔서, 꼭 스펙에 없어도 이런 추가기능은 있는 게 맞다 싶으면 구현해주세요!
여유 되시면 과제 피드백 설문 등도 참여해 주세요! 피드백 하나하나가 많은 도움이 됩니다. 추가적으로 세미나에 대한 제안이나 그런 거 있으셔도 해주셔도 좋아요. 일부러 실명이면 말 못할 만한 것들 많은 것 같아서 만든 익명 창구입니다 (물론 강제 참여는 아닙니다ㅎ)
세미나는 리액트 공부의 보조장치이고, 본인의 개인적인 공부 프로세스가 있으셔야 한다는 거 리마인드 드립니다
저도 자주 틀립니다! 항상 제가 하는 말들에 대해 의심을 하고 왜 그런지 궁금해하시는 게 좋습니다
과제 스펙이 쉬워지고 있는 만큼 만들어 내는 것에서 끝내지 말고, 코드 디자인: 좋은 코드를 짜는 법에 대한 고민을 많이 해 보시는 걸 추천드립니다. 슬슬 어느 정도 리액트 코딩 경험이 생기고 계시기 때문에 "아 이거 이렇게 쓰니까 좋네" "아 이거 왜 이렇게 짰냐" 같은 생각을 하실 시기일 것 같습니다. 물론 점점 학기가 바빠지며 와플에 쏟을 수 있는 시간이 줄어들고 계시리라 예상하지만, 그래도 최대한 많이 고민해보시고, 많이 질문해주시고, 같이 공부할 수 있으면 좋을 것 같아요!
리액트 세미나 2 과제 공통 피드백
나름 세미나 1 과제보다는 쉽게 냈지만, 그래도 안 알려드린 부분이 많아 걱정하고 있었는데 다들 잘 해 주셔서 만족?스러웠던 과제였습니다! 배포 부분도 분명 처음 해 본다면 상당히 부담되는 내용인데, 잘 해결해주신 것 같습니다. 수고하셨어요!
공통 피드백 시작하겠습니다.
Context API의 사용
수업 시간에 설명드렸듯이 Context API는 Props Drilling을 하지 않아도 되게 해 주는 역할 딱 하나를 담당합니다. 또한 이를 응용한 Context best practice 코드는 데이터를 앱 전체에서 전역으로 사용할 수 있도록 도와줍니다. 따라서 불필요하고 더럽게 props를 넘기는 상황을 방지할 수 있습니다.
하지만 당연히 전역 데이터라는 것은 아주 조심스럽게 사용해야 합니다.
먼저 리액트의 특성상 성능 문제가 따릅니다. best practice대로면 Context Provider Component가 앱 최상단에 위치하기 때문에, 이 친구의
state
가 변경되면 앱 전체가 리렌더됩니다. 즉 만약 검색어 인풋 텍스트를 state로 관리했다면, 키보드를 한 번 입력할 때마다 앱 전체 페이지가 리렌더되는 대참사가 일어나게 됩니다.가독성 측면에서도, 전역 데이터가 불필요하게 많은 것은 좋지 않습니다. 전역 상태로 있어서 뭐 하는 친구인지 봤더니 필터 인풋 텍스트가 있다면, 다른 사람의 눈에는 이게 왜 여기 있는지 궁금해집니다. Context에 모든 state를 때려박는 것은
App.js
에 모든 state를 때려박는 것과 마찬가지입니다. (사실 더 책임이 큽니다: App보다도 더 위에 있으니)리팩토링할 때도 좋지 않습니다. 전역 데이터라는 것은 많은 곳에서 이 데이터를 사용하고 있을 수 있다는 가능성을 내포합니다. 때문에 전역으로 디자인된 그 코드를 나중에 고치고 싶을 때 부담이 많이 될 수 있습니다.
추가로, Context를 목적과 제공하는 값에 따라 잘 분류해야 합니다. 가령 학생 목록을 제공하는 Provider에 로그인 정보가 들어있는 것은 좋지 않습니다. 로그인 정보는 따로
AuthContext
라든가 그런 곳에 있는 게 옳습니다. 물론 기능이나 성능상 차이는 없으나, 코드를 의미에 맞게 잘 분리하는 건 중요합니다. 한국말을 할 때 "나는 집에서 딸기를 먹고 학교에서 바나나를 먹었어"라고 하는 것과 "나는 딸기와 바나나를 집과 학교에서 각각 먹었어"라고 하는 것 중 전자가 훨씬 이해가 잘 됩니다. 이것과 유사한 이유라고 생각해주시면 됩니다.제가 이 과제를 혼자 구현해봤을 때는 아래와 같이 디자인했습니다.
이외의 모든 상태를 각 컴포넌트의 state에 적합하게 집어넣어 구현하였습니다. 여담으로 당연히 과제 3도 미리 구현해 봤는데, 이때는 어차피 학생 추가나 삭제 등의 로직을 서버가 모두 담당하기 때문에 StudentDataContext가 딱히 필요가 없어졌습니다. 그래서 저는 로그인 정보 (AuthContext) 하나만 Context로 관리했습니다. 로그인 정보가 바뀌는 건 자주 있는 일도 아니고, 그 경우 앱 전체가 리렌더되는 건 너무 당연하니까요!
여기까지 읽으면 다음과 같은 의문이 들 수 있습니다.
뭐 일단 제 취향은 그렇습니다. 제가 개인적으로 / 회사에서 / 팀에서 프로젝트를 진행할 때 전역으로 저장하는 값은 대부분의 상황에서 로그인 정보 하나뿐입니다. (리덕스를 쓴다면 말이 다르지만요)
하지만, 꼭 Context를 적게 써야 한다고 단정지을 수는 없습니다. 전역으로 쓸 만한 값들이 많을 수도 있죠. 또한 페이지의 특성에 따라 best practice처럼 사용하지 않고, 그냥 컴포넌트 자체에서 바로
Context.Provider
불러서 provide할 경우도 있을 수 있습니다. 리액트는 언제나 자유로운 코드 문화를 가지고 있었기에 항상 "이렇다" 라고 말할 수 있는 건 거의 없습니다.아무튼 중요한 건 본인의 앱이 어떻게 돌아가는지 확실하게 이해하는 거예요. Context에 많은 데이터를 넣을수록 성능에 부담이 된다 (너무 큰 규모의 많은 리렌더가 일어나니까)는 걸 이해하고 계신 게 중요합니다. 그리고 그걸 이해하고 계시다면, 적어도 이번 과제에서는 어느 정도의 props drilling을 감수하더라도 저와 같이 디자인하는 게 좋을 거란 의견에 동의하실 것 같네요!
로그인 정보 유지
로그인 정보 유지를 위해
localStorage
를 사용하신 분들이 많았습니다. 잘 구현해 주셨더라고요 👍하지만 일단 localStorage가 state보다 접근하는 데 더 오래 걸립니다. 또한 localStorage의 데이터는 mutable하므로 자주 접근하게 되면 리액트스럽지 않아집니다.
따라서 로그인 정보는 항상 state에 저장해 두고, localStorage는 정말 딱 "백업용"으로, 앱 켜질 때 / 로그인할 때 / 로그아웃할 때 말고는 한 번도 접근하지 않는 게 좋습니다. 가령 App.js에서
localStorage.getItem()
하여 로그인 상태를 확인하는 등은 바람직하지 않겠군요기타
camelCase
PascalCase
제발 지켜주시길 간곡히 부탁드립니다..515 참고하셔서, 꼭 스펙에 없어도 이런 추가기능은 있는 게 맞다 싶으면 구현해주세요!