728x90

온라인 강좌를 듣고 Provider 상태관리를 Riverpod 로 변경해보고 있다.

구글 검색으로 많이 나오는 Todo 에 예제와 비슷한 예제이다.

import 'package:bucket_list/view/home_page.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
 
void main() {
  runApp(
    ProviderScope(
      child: const MyApp(),
    ),
  );
}
 
class MyApp extends StatelessWidget {
  const MyApp({super.key});
 
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: HomePage(),
    );
  }
}

 

import 'package:bucket_list/provider/bucket_provider.dart';
import 'package:bucket_list/view/create_page.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
 
class HomePage extends ConsumerStatefulWidget {
  const HomePage({super.key});
 
  @override
  ConsumerState<HomePage> createState() => _HomePageState();
}
 
class _HomePageState extends ConsumerState<HomePage> {
 
  @override
  Widget build(BuildContext context) {
    final bucketList = ref.watch(bucketProvider);
 
    return Scaffold(
      appBar: AppBar(
        title: Text("버킷 리스트"),
        centerTitle: true,
      ),
      body: bucketList.isEmpty
          ? Center(child: Text("버킷 리스트를 작성해 주세요."))
          : ListView.builder(
        itemCount: bucketList.length// bucketList 개수 만큼 보여주기
        itemBuilder: (context, index) {
          final bucket = bucketList[index]; // index에 해당하는 bucket 가져오기
          return ListTile(
            // 버킷 리스트 할 일
            title: Text(
              bucket.job,
              style: TextStyle(
                fontSize: 24,
                color: bucket.isDone ? Colors.grey : Colors.black,
                decoration: bucket.isDone
                    ? TextDecoration.lineThrough
                    : TextDecoration.none,
              ),
            ),
            // 삭제 아이콘 버튼
            trailing: IconButton(
              icon: Icon(CupertinoIcons.delete),
              onPressed: () {
                // 삭제 버튼 클릭시
                showDeleteDialog(context, index);
              },
            ),
            onTap: () {
              bucket.isDone = !bucket.isDone;
              //bucketService.updateBucket(bucket, index);
              ref.read(bucketProvider.notifier).updateBucket(bucket);
            },
          );
        },
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add),
        onPressed: () async {
          // + 버튼 클릭시 버킷 생성 페이지로 이동
          String? job = await Navigator.push(
            context,
            MaterialPageRoute(builder: (_) => CreatePage()),
          );
        },
      ),
    );
  }
 
  void showDeleteDialog(
      BuildContext context, int index) {
    showDialog(
      context: context,
      builder: (context) {
        return AlertDialog(
          title: Text("정말로 삭제하시겠습니까?"),
          actions: [
            // 취소 버튼
            TextButton(
              onPressed: () {
                Navigator.pop(context);
              },
              child: Text("취소"),
            ),
            // 확인 버튼
            TextButton(
              onPressed: () {
                //bucketService.deleteBucket(index);
                ref.read(bucketProvider.notifier).deleteBucket(index);
                Navigator.pop(context);
              },
              child: Text(
                "확인",
                style: TextStyle(color: Colors.pink),
              ),
            ),
          ],
        );
      },
    );
  }
}
 

 

import 'package:bucket_list/provider/bucket_provider.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
 
class CreatePage extends ConsumerStatefulWidget {
  const CreatePage({super.key});
 
  @override
  ConsumerState<CreatePage> createState() => _CreatePageState();
}
 
class _CreatePageState extends ConsumerState<CreatePage> {
  // TextField의 값을 가져올 때 사용합니다.
  TextEditingController textController = TextEditingController();
 
  // 경고 메세지
  String? error;
 
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("버킷리스트 작성"),
        // 뒤로가기 버튼
        leading: IconButton(
          icon: Icon(CupertinoIcons.chevron_back),
          onPressed: () {
            Navigator.pop(context);
          },
        ),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          children: [
            // 텍스트 입력창
            TextField(
              controller: textController, // 연결해 줍니다.
              autofocus: true,
              decoration: InputDecoration(
                hintText: "하고 싶은 일을 입력하세요",
                errorText: error,
              ),
            ),
            SizedBox(height: 32),
            // 추가하기 버튼
            SizedBox(
              width: double.infinity,
              height: 48,
              child: ElevatedButton(
                child: Text("추가하기", style: TextStyle(fontSize: 18)),
                onPressed: () {
                  // 추가하기 버튼 클릭시
                  String job = textController.text; // 값 가져오기
                  if (job.isEmpty) {
                    setState(() {
                      error = "내용을 입력해주세요."// 내용이 없는 경우 에러 메세지
                    });
                  } else {
                    setState(() {
                      error = null// 내용이 있는 경우 에러 메세지 숨기기
                    });
 
                    // BucketService 가져오기
                    //BucketService bucketService = context.read<BucketService>();
                    //bucketService.createBucket(job);
                    ref.read(bucketProvider.notifier).createBucket(job);
 
                    Navigator.pop(context, job); // job 변수를 반환하며 화면을 종료합니다.
                  }
                },
              ),
            ),
          ],
        ),
      ),
    );
  }
}
 
 

 

/// 버킷 클래스
class Bucket {
  String id;
  String job; // 할 일
  bool isDone; // 완료 여부
 
  Bucket(this.id, this.job, this.isDone); // 생성자
}
 

 

import 'package:bucket_list/model/bucket.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
 
final bucketProvider = NotifierProvider<BucketNotifier, List<Bucket>>(BucketNotifier.new);
 
class BucketNotifier extends Notifier<List<Bucket>> {
  @override
  List<Bucket> build() => [];
 
  /// bucket 추가
  void createBucket(String job){
    state = [...state, Bucket((state.length + 1).toString(),job, false)];
  }
 
  /// bucket 수정
  void updateBucket(Bucket bucket){
    state = [
      for(final item in state)
        if(item.id == bucket.id)
          Bucket(item.id, bucket.job, bucket.isDone)
        else
          item
    ];
  }
 
  /// bucket 삭제
  void deleteBucket(int index){
    //state = state.where((e) => e.id != bucket.id).toList(); // Bucket bucket 인자로 받을 때
    state = List.from(state)..removeAt(index);
  }
}

 

Riverpod Notifier로 구현한 코드와

Provider 로 구현한 BucketService 코드를

비교해서 보면 도움이 될 거 같다.

 

import 'package:burket_list/model/bucket.dart';
import 'package:flutter/material.dart';
 
class BucketService extends ChangeNotifier {
  List<Bucket> bucketList = [];
 
  /// bucket 추가
  void createBucket(String job){
    bucketList.add(Bucket(job, false));
    notifyListeners();
  }
 
  /// bucket 수정
  void updateBucket(Bucket bucket, int index){
    bucketList[index] = bucket;
    notifyListeners();
  }
 
  /// bucket 삭제
  void deleteBucket(int index){
    bucketList.removeAt(index);
    notifyListeners();
  }
}
 
/***
 * 전역적으로 사용되는 데이터를 담당할 서비스를 만들고,
 * 해당 데이터에 대한 CRUD를 모두 해당 서비스에서 구현한다.
 */

 

 

'Flutter 앱 > 상태관리' 카테고리의 다른 글

Flutter riverpod 자동 생성  (0) 2024.01.15
Flutter Provider 상태관리 예제  (0) 2024.01.06
Flutter StatefulWidget  (0) 2023.12.13
Flutter Riverpod - NotifierProvider.family  (0) 2023.12.11
Flutter Riverpod - NotifierProvider  (0) 2023.12.11
블로그 이미지

Link2Me

,