[Flutter] Pagination-④Restaurant Pagination 요청하기

겨레·2024년 7월 15일
0

이전 거는 샘플로 데이터를 넣어 둔 건데,
이제 실제로 데이터를 가져와서 RestaurantCard에 넣는 작업을 해 볼 거임!


이건 API 속성들인데... API 속성들과 이름을 똑같이 사용하면 싱크를 맞추기 쉬움.


근데 몇 개 다른 게 있어서 restaurant_card.dart 코드로 가서 수정해주겠음.


이제 본격적으로 Restaurant Pagination 요청해보자!

① Future Builder 사용해보기
Future Builder를 사용하려면 Future 함수가 필요하다.

Future의 값을 리턴해주는 함수인데, 여기선 어떤 값을 리턴해줄까?
API 요청에서 data에 해당하는 부분이다. (List에 해당되는 20개의 data)


이 부분만 따로 반환해주는 함수를 만들어보자.
restaurant_screen.dart 코드로 가자.

(+) 왜 Future로 반환할까? 👉 async 함수를 선언했기 때문!
그럼 왜 async로 선언했을까? 👉 http 요청할 거라서

② Future Builder 넣어 보기
밑으로 가서 RestaurantCard 이 부분을

아래와 같이 수정해준다.

저장하고 재실행하면 디버그 콘솔 창에 이렇게 null이 반환되는 걸 볼 수 있다.

print(snapshot.error); 해서 어떤 오류인지 확인해보자.
401에러는 토큰이 잘못됐을 때 발생하는 에러임!

왜 401 에러가 났을까?

accessToken storage에서 가져왔는데 이 accessToken의 유효 기간은 5분임.
현재 5분이 지나버려서 만료된 accessToken을 요청에 넣었다 보니
토큰이 만료됐다고 401 에러를 던지는 것!

그럼 어떻게 해야할까???

refreshToken을 사용해 갱신을 또 해 주면 됨!
지금은 splash_screen.dart 코드로 가서 발급받은 토큰을 저장하는 코드를 추가해 준다.
(어떤 상황이든 무조건 자동 갱신해 주는 로직도 추후 작성할 예정)

이제 refreshToken에 문제가 없다면, 스플래시 스크린이 실행되면서
checkToken이 실행되어 앱 재실행 때마다 토큰이 개신됨!
그리고 만약 토큰에 문제가 있다면 로그인 화면으로 전환될 거임.


재실행 하면 이렇게 data가 잘 나오는 것도 확인할 수 있음.


③ restaurant_screen.dart 코드 수정

import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter_actual/common/const/data.dart';
import 'package:flutter_actual/restaurant/component/restaurant_card.dart';

class RestaurantScreen extends StatelessWidget {
  const RestaurantScreen({super.key});

  Future<List> paginateRestaurant() async {
    final dio = Dio();

    final accessToken = await storage.read(key: ACCESS_TOKEN_KEY);
    final resp = await dio.get(
      'http://$ip/restaurant',
      options: Options(
        headers: {
          'authorization': 'Bearer $accessToken',
        },
      ),
    );
    // return resp.data를 하면 실제 바디 가져올 수 있음!
    // 그런데 내가 가져오고 싶은 값은?
    // data라는 키 안에 있는 값들만 반환할 거임!! -> 그래야 List 값을 가져올 수 있기에...
    return resp.data['data'];
  }

  
  Widget build(BuildContext context) {
    return Container(
      child: Center(
        child: Padding(
          padding: const EdgeInsets.symmetric(horizontal: 16),
          // <List>를 사용해 어떤 값이 들어오는지 확인
          child: FutureBuilder<List>(
            future: paginateRestaurant(),
            builder: (context, AsyncSnapshot<List> snapshot) {
              // 만약 snapshot에 data가 없으면
              if (!snapshot.hasData) {
                return Container();
              }
              // data가 있으면 ListView를 리턴
              return ListView.separated(
                // itemCount에는 몇 개의 아이템을 넣을 건지
                itemCount: snapshot.data!.length,
                // itemBuilder는 index를 받아서 각 아이템별로 렌더링
                itemBuilder: (_, index) {
                  return RestaurantCard(
                    image: Image.asset('asset/img/food/ddeok_bok_gi.jpg',
                        fit: BoxFit.cover),
                    name: '불타는 떡볶이',
                    tags: const ['떡볶이', '치즈', '매운맛'],
                    ratingsCount: 100,
                    deliveryTime: 15,
                    deliveryFee: 2000,
                    ratings: 4.52,
                  );
                },
                // separatorBuilder => 각 아이템 사이사이에 들어가는 거를 빌드
                separatorBuilder: (_, index) {
                  return const SizedBox(
                    height: 16,
                  );
                },
              );
            },
          ),
        ),
      ),
    );
  }
}


그 결과!!!
List로 20개의 레스토랑 카드들이 렌더링 됨!



④ 각 가게 별 리스트 나오게 하기
하지만 불타는 떡볶이만 나오고 있음... 왜냐면 똑같은 값들을 반환하도록 했으니까.
이제 각 가게 별 리스트가 나오도록 해보자!


restaurant_screen.dart 코드 수정해주기.

그런데 실행하면 이런 오류가 발생함.

List<String> 타입이 들어와야 하는데 List<dynamic>이 들어왔다는 에러!
List<dynamic>타입을 List<String> 타입으로 바꿔주자!

tags: List<String>.from(item['tags']) 이렇게!



수정 후, 저장하고 재실행하면!!! 짠~!!!

profile
호떡 신문지에서 개발자로 환생

0개의 댓글