[코드팩토리] [중급] Flutter 진짜 실전! 상태관리, 캐시관리, Code Generation, GoRouter, 인증로직 등 중수가 되기 위한 필수 스킬들!
안녕하세요 선생님! 초급, 중급 강의 들으면서 riverpod 와 drift를 사용해서 MVVM패턴으로 간단한 코드를 작성 하였는데 에러가 발생하여 질문 드립니다. _onTap으로 생성을 시도하면 point2번까지는 값이 잘 전달되는데 다음과 같은 오류가 발생합니다. ##### 오류 내용 ##### [VERBOSE-2:dart_vm_initializer.cc(41)] Unhandled Exception: SqliteException(1299): while executing statement, NOT NULL constraint failed: counter_model.value, constraint failed (code 1299) Causing statement: INSERT INTO "counter_model" ("title") VALUES (?), parameters: TextName 답변 부탁 드리겠습니다. 감사합니다!
[코드팩토리] [중급] Flutter 진짜 실전! 상태관리, 캐시관리, Code Generation, GoRouter, 인증로직 등 중수가 되기 위한 필수 스킬들!
섹션 11 > Pagination 일반화하기 > RatingsPagination 렌더링하기 수강 중인데 "type 'Null' is not a subtype of type 'List<dynamic>' in type cast"라서 RatingCard가 나오지 않는데 어디서 부터 확인해야할 지 모르겠습니다... ㅠㅠ flutter: [RES] [GET] http://127.0.0.1:3000/restaurant/5ac83bfb-f2b5-55f4-be3c-564be3f01a5b/rating/?count=20 flutter: type 'Null' is not a subtype of type 'List<dynamic>' in type cast flutter: #0 $RatingModelFromJson (package:actual/rating/model/rating model.g.dart:14:62) #1 new RatingModel.fromJson (package:actual/rating/model/rating_model.dart:27:62) #2 RestaurantRatingRepository.paginate.<anonymous closure> (package:actual/restaurant/repository/restaurant rating_repository.g.dart:46:29) #3 MappedListIterable.elementAt (dart:_internal/iterable.dart:415:31) #4 ListIterator.moveNext (dart:_internal/iterable.dart:344:26) #5 new GrowableList. ofEfficientLengthIterable (dart:core-patch/growable_array.dart:189:27) #6 new GrowableList.of (dart:core-patch/growable array.dart:150:28) #7 new List.of (dart:core-patch/array_patch.dart:47:28) #8 ListIterable.toList (dart:_internal/iterable.dart:214:7) #9 $CursorPaginationModelFromJson (package:actual/common/model/cursor pagination_model.g.dart:15:60) #10 new CursorPaginationModel.fromJson (package:actual/common/model/cursor_pagination_model.dart:44:108) #11 _RestaurantRatin<…> flutter: Instance of 'CursorPaginationModelError'
[코드팩토리] [중급] Flutter 진짜 실전! 상태관리, 캐시관리, Code Generation, GoRouter, 인증로직 등 중수가 되기 위한 필수 스킬들!
안녕하세요! dio 활용한 http 요청 처리에 대해 질문이 있습니다. 해당 프로젝트의 경우 http 요청의 response body에 맞는 model을 jsonSerializable로 생성하고, 해당 model을 return type으로 갖는 함수를 repository에 선언하여 response body를 model.fromJson 형태로 가져오는 걸로 이해했습니다. 하지만 이 경우 response body가 기존에 선언한 model의 형태와 동일한 경우에만 fromJson으로 받아올 수 있고, 다른 에러 코드 등(400 BAD_REQUEST)에 의해 response body가 다른 형태로 오게 된다면 처리가 불가능 할 것 같습니다. 이런 경우 프론트엔드에서 요청 처리를 어떻게 진행해야 하나요? repository의 함수에서 response.data 만 return 해주는 경우 해당 함수를 호출하는 다른 provider에서는 예외 처리가 어려울 것 같아서 질문드립니다!
[코드팩토리] [중급] Flutter 진짜 실전! 상태관리, 캐시관리, Code Generation, GoRouter, 인증로직 등 중수가 되기 위한 필수 스킬들!
Restaurant 와 RestaurantDetail 가 서로 연결될 수 있게 설계를 했기 때문에, detail 캐싱이 가능한걸까요? 현업에서 강의와 다르게 설계가 되어 있다면 별도의 상태를 하나 더 만들어야 할까요? ==== 억지 가정 ==== 현업에서 Restaurant 의 이미지는 thumbUrl 로, RestaurantDetail 의 이미지는 detailThumbUrl 로 설계가 되어 있다는 가정
[코드팩토리] [중급] Flutter 진짜 실전! 상태관리, 캐시관리, Code Generation, GoRouter, 인증로직 등 중수가 되기 위한 필수 스킬들!
authProvider로 루트 설정하는거 정말 최고예요..!! 항상 좋은 강의에 감사드립니다! 강의 듣다가 하나 궁금한 점이 있는데, 보통 스플래시 화면에서 데이터를 미리 불러온다던지 일부러 1-2초 일정한 딜레이를 건다거나 스플래시에 움직이는 애니메이션을 넣는 경우에는 이런 authProvider에서 어떻게 해결해야하나요? redirectLogic 안에서 isInitialized라고 지정해둔 변수를 이용해서 해봤는데 이게 맞는지ㅠ 좀 더러운거같아서 여쭤봅니다! Future<String?> redirectLogic( BuildContext context, GoRouterState state) async { if (!isInitialized) { isInitialized = true; return '/splash'; } if (isInitialized) { await Future.wait([ Future.delayed(const Duration(seconds: 1)), // 1초 지연 ]); } final UserBase? user = await ref.read(userProvider); // print('redirectLogic - user : ${user.toString()}'); final loggingIn = state.location == '/login'; // 유저 정보가 없는데 // 로그인중이면 그대로 로그인 페이지에 두고 // 만약에 로그인중이 아니라면 로그인 페이지로 이동 if (user == null) { return loggingIn ? null : '/login'; } if (user is UserModel && loggingIn || state.location == '/splash') { // 여기서 미리 가져오면 좋을 데이터를 가져오기 } // user가 null이 아님 // UserModel // 사용자 정보가 있는 상태면 // 로그인 중이거나 현재 위치가 SplashScreen이면 // 홈으로 이동 if (user is UserModel) { return loggingIn || state.location == '/splash' ? '/' : null; } // UserModelError if (user is UserError) { return !loggingIn ? '/login' : null; } return null; }
[코드팩토리] [중급] Flutter 진짜 실전! 상태관리, 캐시관리, Code Generation, GoRouter, 인증로직 등 중수가 되기 위한 필수 스킬들!
중급반 섹션6 <Dio onError Interceptor 작업하기>강의 8분 정도에 onError작업하는 과정에서 에러사항 처리하는 과정에서 refresh토큰으로 accessToken 요청경로가 아래 같은 경로로 설정하셨는데, final isPathRefresh = err.requestOptions.path == '/auth/token'; restaurnatRepository 에서 baseUrl을 이렇게 설정하셨는데 강의처럼 설정하면 http로 시작안하면 baseUrl이 온다고 나와있어서 'http://$ip/restaurant' /// If the `path` starts with 'http(s)', the `baseURL` will be ignored, otherwise, /// it will be combined and then resolved with the baseUrl. 'http://$ip/restaurant/auth/token'이 이렇게 되는게 아닌지 궁금합니다. +그리고 Riverpod pdf자료 추가 안되어있는거 같은데 이것도 확인한번부탁드릴게요~ㅎ
[코드팩토리] [중급] Flutter 진짜 실전! 상태관리, 캐시관리, Code Generation, GoRouter, 인증로직 등 중수가 되기 위한 필수 스킬들!
안녕하세요! 단어간 중간에 점을 찍는다던가, 아이콘을 텍스트와 묶어서 위젯으로 반환한다던가 하는 일을 할때, 언제는 그냥 함수로 구현하고, 언제는 stless 클래스를 만들어서 build하는 형식으로 구현하는데, 이 두가지 방법 중 선택하는데 기준이 있나요? 이 둘의 차이점을 크게 모르겠습니다.
[코드팩토리] [중급] Flutter 진짜 실전! 상태관리, 캐시관리, Code Generation, GoRouter, 인증로직 등 중수가 되기 위한 필수 스킬들!
안녕하세요 코팩님 로그인 처리시 로그인 방식에 차이가 있는지 여쭈어 보고 싶습니다. 강의에서는 refresh token과 access token을 이용한 방식을 사용하는걸로 알고 있는데요.. 현재 저희 회사에서 진행하고 있는 프로젝트에서 선임분께서는 다음과 같은 방식으로 로그인 코드를 작성하였는데요.. 무슨 차이인지 여쭈어보고 싶습니다. [login.Screen.dart]
[코드팩토리] [중급] Flutter 진짜 실전! 상태관리, 캐시관리, Code Generation, GoRouter, 인증로직 등 중수가 되기 위한 필수 스킬들!
안녕하세요. 기초를 수강하고, 중급 강의 절반 정도 수강한 학생입니다. 우선, 기초와 중급 모두 좋은 퀄리티의 영상과 강의를 올려주셔서 정말 감사드린다는 말씀 드립니다! 현재 강의와는 별개로 따로 진행하고 있는 프로젝트에서 한 페이지에 여러 api 호출을 진행하는 과정에서 access 토큰이 만료되었을 때의 상황에서 문제를 겪고 있습니다. 예를 들어, 3개의 api를 호출하여 FutureBuilder 3개 혹은 Future.wait으로 3개의 데이터를 가져오는 상황입니다. 우선, 모든 요청에 access 토큰 만료를 백엔드에서 계산하고 있습니다. 만료가 되었을 때, 프론트로 401이 던져지고 onError에서 이를 캐치하여 재발급 api를 호출하고 다시 토큰을 갱신하여 secure storage에 저장하고 있습니다. (백엔드에서는 access 토큰이 만료되어 재발급 요청을 받으면, 유효한 refresh 토큰인지 확인하여 유효시 두 토큰 모두 갱신하여 재발급해줍니다.) 이 과정에서 3개의 모든 api 요청에 대한 재발급을 시도하여 3번의 재발급 요청이 이루어지게 됩니다. 그리고나서 3개의 모든 api 요청에 다시 resolve를 하게 되는데, 이러한 순서의 로직이 맞는 부분인지 궁금합니다. 어려움을 겪고 있는 부분에는 3개의 요청 중 2개의 요청은 요청된 시간이 밀리세컨드 단위로 다르지만, 재발급 된 토큰이 동일해 요청이 성공적으로 진행됩니다. (5개라면 2개가 성공할 때가 있고, 3개가 성공할 때가 있고 시시각각 변합니다..) 하지만, 남은 api 요청은 앞선 요청에서 이미 새롭게 토큰이 발급되었기 때문에 갱신되지 않은 토큰으로 요청을 보내게 되고, 서버에서는 토큰이 새로 갱신되었기 때문에 토큰이 유효하지 않다는 오류가 발생하게 됩니다. 여러 레퍼런스를 참고하여 QueuedInterceptorsWrapper 및 일부 코드를 추가하여 임시로 해결해놓은 상태이지만, 근본적인 원인 해결이 되지 않았다고 생각하여 질문드립니다. (여전히 5개의 요청이라면, 5개의 재발급 요청을 보내는 상황입니다...) 아직 남은 강의를 모두 들어보지 않아 해결하지 못하는 문제일 수 있지만, 미리 질문부터 드리는 점 양해 드립니다,,ㅠ 서둘러 완강해보도록 하겠습니다! 감사합니다 :)
[코드팩토리] [중급] Flutter 진짜 실전! 상태관리, 캐시관리, Code Generation, GoRouter, 인증로직 등 중수가 되기 위한 필수 스킬들!
안녕하세요 선생님 해당 강의내용에서 당겨서 새로고침하는 리프레쉬 인디케이터를 사용하면 상단에 로딩바가 하나 도는데 다시 화면이 리프레쉬되면서 화면 중앙에 로딩바가 도는 것이 2중 로딩으로 보여지는 것 같아서 pagination_list_view.dart 파일내 RefreshIndicator( onRefresh: () async { ref.read(widget.provider.notifier).paginate(forceRefetch: true); }, 위 코드의 forceRefetch: true 를 삭제하는게 더 낫겠다는 판단에 RefreshIndicator( onRefresh: () async { ref.read(widget.provider.notifier).paginate(); }, 해당코드를 사용 하려 하는데요 근데 이렇게 포스리펫치를 삭제 하게 되면 [홈] 메뉴와 [음식] 메뉴에서는 정상적으로 REQ RES 포스트 겟 요청이 가는데 [주문] 메뉴에서는 아무런 응답이 없어서 새로고침이 되지 않습니다. 현재 강의에서 장바구니에서 주문완료를 눌러도 장바구니 내용이 비워지지 않는 문제와 로딩이 이중으로 되는 문제를 확인했는데 장바구니 부분은 주문완료버튼을 눌렀을때 주문내용을 비워버리면 해결 될 것 같다는 개념이라도 잡히는데 포스리펫치 부분은 어디서 손을 대야 될지 아직 개념이 잡히지 않는데요 홈메뉴와 음식메뉴에서는 forceRefetch:true가 아니더라도 서버에서 자료를 받는 로직이 있는데 주문메뉴에서는 앱에서 발생된 주문건에 대해서만 받아오는 로직이라 그게 아닌가? 싶은 생각만 듭니다. 1.앱을 처음 로딩해서 주문메뉴에 들어갔을때 -> 로딩이 강제로 되니 새로운 주문건이 화면에 표시됨 2.포스리팻치 true일경우 -> 강제 새로고침기능이 작동하니 새로운 주문건이 화면에 표시됨 3.포스리팻치를 삭제하고 리프레쉬인디게이터만 사용할경우 -> 새로운 주문건이 표시가 안됨. 어떤 부분을 확인하거나 살펴보는게 좋을지 힌트를 주셨으면 좋겠습니다. 만일 forceRefetch:true를 꼭 사용해야 되는 설계라면 로딩바 대신에 스켈레톤을 사용한다면 2중 로딩느낌이 안날 것 같다는 생각이 듭니다.
[코드팩토리] [중급] Flutter 진짜 실전! 상태관리, 캐시관리, Code Generation, GoRouter, 인증로직 등 중수가 되기 위한 필수 스킬들!
simulatorIP와 emulatorIP가 빨간색 줄로 나타나며 The instance member 'simulatorIP' can't be accessed in an initializer 다음과 같은 오류가 발생합니다. Stackoverflow를 통해 찾아보았으나 구체적으로 무슨 오류인지 파악하기가 어려워 질문드리고자 합니다.