Notice
Recent Posts
Recent Comments
Link
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 | 31 |
Tags
- Clean Architecture
- java 콘솔 출력 차이
- JQ
- react
- 자바 출력 방식
- Flutter
- LLM
- 배포
- java 출력
- abap
- lifecycle
- 단축키
- java
- UI/UX
- npm
- riverpod
- DART
- printf
- firebase
- unity
- ListView
- JS
- nodejs
- 자바스크립트
- scss
- develop
- println
- 자바 포맷 출력
- 앱심사
- 엡
Archives
- Today
- Total
guricode
[flutter]자취의 정석 -7 커뮤니티 목록 안 뜸 / ref dispose 오류 본문
증상
- 게시글 리스트가 로드되지 않거나 계속 로딩.
- 콘솔에 Bad state: Cannot use "ref" after the widget was disposed. 발생.
- WidgetsBinding.instance.addPostFrameCallback로 loadInitial 호출 시에도 간헐적으로 동일.
원인
- build() 안에서 provider를 새로 생성 → initState()에서 로드한 provider와 다른 인스턴스를 watch 하게 되어 초기 로드가 해당 인스턴스에 적용되지 않음.
- 위치(location)가 나중에 들어오는 비동기 흐름을 고려하지 않음 → provider를 만들 시점이 불명확.
- 프레임 콜백/스케줄러 타이밍에 ref 접근 → 위젯 dispose 이후 실행되면 ref 사용 불가 오류.
해결
- provider를 필드로 한 번만 생성하고,
initState() / didUpdateWidget()에서만 초기화 + 1회 로드. - build()에서는 이미 만든 provider만 watch.
- location이 나중에 들어오면 didUpdateWidget()에서 provider를 재초기화.
- addPostFrameCallback 제거(필요 없음).
수정 코드 (핵심 부분)
class _PostsPlaceholderState extends ConsumerState<_PostsPlaceholder> {
// build에 의존하지 않는 고정 provider
late NotifierProvider<CommunityListVM, CommunityListState> provider;
bool _ready = false; // provider 준비 여부
// 댓글수 캐시
final Map<String, Future<int>> _commentCountFutures = {};
@override
void initState() {
super.initState();
_maybeInitProviderAndLoad();
}
@override
void didUpdateWidget(covariant _PostsPlaceholder oldWidget) {
super.didUpdateWidget(oldWidget);
// location이 뒤늦게 생기거나 변경되면 재초기화
if (oldWidget.location != widget.location) {
_ready = false;
_maybeInitProviderAndLoad();
}
}
void _maybeInitProviderAndLoad() {
final loc = widget.location;
if (loc == null || loc.isEmpty) return; // 아직 준비 안 됨
provider = communityListVmProvider(
categoryCode: widget.parentCode,
detailCode: widget.detailCode,
location: loc,
);
_ready = true;
// 초기 로드 1회
Future.microtask(() {
if (!mounted) return;
ref.read(provider.notifier).loadInitial(ref);
});
}
@override
Widget build(BuildContext context) {
if (!_ready) return const NoLocationView(); // 위치 없거나 아직 준비 전
// ★ build에서는 필드 provider만 watch (다시 만들지 말기!)
final st = ref.watch(provider);
return Scaffold(
body: NotificationListener<ScrollNotification>(
onNotification: (n) {
if (!st.hasMore || st.isLoading) return false;
if (n.metrics.pixels >= n.metrics.maxScrollExtent * 0.9) {
ref.read(provider.notifier).loadMore(ref);
}
return false;
},
child: Column(
children: [
// ... 기존 헤더/정렬 UI ...
Expanded(
child: ListView.separated(
padding: const EdgeInsets.only(left: 24, right: 24, bottom: 100),
itemCount: st.items.length + ((st.isLoading && st.hasMore) ? 1 : 0),
separatorBuilder: (_, __) => const SizedBox(height: 12),
itemBuilder: (_, i) {
if (i >= st.items.length) {
return const Center(
child: Padding(
padding: EdgeInsets.all(16),
child: CircularProgressIndicator(),
),
);
}
final x = st.items[i];
// ... 기존 셀 UI (NickName, 댓글 수 Future, 날짜 등) ...
// _commentCountFutures 활용 로직 그대로 유지
return /* 기존 InkWell 카드 */;
},
),
),
],
),
),
);
}
}
체크리스트
- provider를 build에서 생성하지 않는다.
- 초기 로드는 initState / didUpdateWidget에서 1회만.
- 비동기 값(location)이 바뀌면 provider 재초기화 후 다시 loadInitial.
- addPostFrameCallback로 ref를 늦게 호출하지 않는다(불필요/위험).
'앱 > Flutter&Dart' 카테고리의 다른 글
| [flutter] 자취의 정석 -9: Firebase 서버시간을 한국시간(KST)으로 정확히 보여주기, FieldValue.serverTimestamp() UTC표준 변환, “N분 전” 구현 (0) | 2025.10.02 |
|---|---|
| [flutter]자취의 정석 -8 게시글, 댓글 페이지네이션 microtask (0) | 2025.10.02 |
| [flutter]자취의 정석 -6 댓글 꾹~ 눌렀을때 메뉴 펼치기(신고하기,차단하기 등등) (0) | 2025.09.22 |
| [flutter]자취의 정석 -5 NestedScrollView를 이용한 스크롤 화면 (0) | 2025.09.20 |
| [flutter]자취의 정석 -4,bottomSheet에 TextFormField 입력시 hassized문제 (0) | 2025.09.19 |