Flutter Study (5)

cheeseonrose·2023년 4월 16일
0

상태 관리(State Management)

상태 관리란

  • 서로 다른 페이지에서 변수를 공유하고, 변수의 값을 바꾸며 여러 페이지의 화면을 한꺼번에 갱신해주기 위한 것
  • 서비스(Service) : 데이터를 담당하는 클래스
  • 각 페이지에서는 데이터에 대한 CRUD를 모두 서비스에게 요청하는 방식으로 구현

상태 관리 패키지

  • GetX
  • Provider
  • BloC
  • Riverpod
  • 사용법이 쉽고, Flutter 공식 문서에서 추천하는 Provider를 사용

Provider 시작하기

  • 설치
    • 터미널에 다음을 입력
    $ flutter pub add provider

MemoService 생성

  • memo_service.dart 파일 생성
    import 'package:flutter/material.dart';
     import 'main.dart';
     
     // Memo는 데이터의 형식을 지정
     class Memo {
     	Memo({
      		required this.content,
      	});
          
        String content;
     )
     
     // Memo의 데이터를 관리하는 곳
     class MemoService extends ChangeNotifier {
     	List<Memo> memoList = [
      		Memo(content: "장보기 목록: 사과, 양파"),	// 더미(dummy) 데이터
            Memo(content: "새 메모"),	// 더미(dummy) 데이터
        ];
     )
  • Provider를 사용하여 MemoService를 Widget tree의 꼭대기에 배치
    • main.dart
    runApp(
    	MultiProvider(
      		providers: [
              	ChangeNotifierProvider(create: (context) => MemoService()),
            ],
            child: const MyApp(),
       	),
     );

메모 앱에 Provider 적용

  • HomePage 전체 위젯을 Consumer로 감싸줌
  • return Scaffold에서 Scaffold를 Wrap with Builder로 감싸주고 Consumer로 변경
    return Consumer<MemoService>(
        builder: (context, memoService, child) {
          return Scaffold(
    			...
    	  );
    	}
     );
  • MemoService에서 값이 변경되는 경우, StatefulWidget의 setState처럼 notifyListeners()를 호출
    -> 해당 서비스의 Consumer로 등록된 모든 Widget의 builder 함수가 재호출 되면서 화면이 갱신됨

메모 목록 조회

  • 메모 리스트 가져오기
    List<Memo> memoList = memoService.memoList;

메모 개별 조회

  • context.read를 이용

    • context.read<클래스명>() : 위젯 트리 상단에 있는 Provider로 등록한 클래스에 접근 가능
    • 화면 새로고침이 필요할 때는 Consumer를, 화면 새로고침 없이 클래스의 변수나 함수만 이용하고자 한다면 context.read<클래스명>()을 사용
    DetailPage({super.key, required this.index});
    
     final int index;
    
     TextEditingController contentController = TextEditingController();
    
     
     Widget build(BuildContext context) {
    	 MemoService memoService = context.read<MemoService>(); 
    	 Memo memo = memoService.memoList[index];
    
    	 contentController.text = memo.content;
    	 ...
     }
  • Navigator 수정

    onTap: () {
    	Navigator.push(
    		context,
    		MaterialPageRoute(
    			builder: (_) => DetailPage(
    				index: index,
    			),
    		),
    	);
    }

메모 작성

  • MemoService에 메모 생성 함수 구현
    createMemo({required String content}) {
    	Memo memo = Memo(content: content);
    	memoList.add(memo);
    	notifyListeners();	// Consumer<MemoService>의 builder 부분을 호출해서 화면을 새로고침
    }
  • FloatingActionButton 수정
    floatingActionButton: FloatingActionButton(
    	child: Icon(Icons.add),
    	onPressed: () {
    	// + 버튼 클릭시 메모 생성 및 수정 페이지로 이동
    		memoService.createMemo(content: "");
    		Navigator.push(
    			context,
    			MaterialPageRoute(
    				builder: (_) =>
    					DetailPage(index: memoService.memoList.length - 1),
                ),
            );
    	}
    )

메모 수정

  • MemoService에 메모 수정 함수 구현
     updateMemo({required int index, required String content}) {
        Memo memo = memoList[index];
        memo.content = content;
        notifyListeners();
    }
  • DetailPage의 TextField 수정
    TextField(
    	...
    	onChanged: (value) {
    		memoService.updateMemo(index: index, content: value);
    	}
    )

메모 삭제

  • MemoService에 메모 삭제 함수 구현
    deleteMemo({required int index}) {
        memoList.removeAt(index);
        notifyListeners();
        saveMemoList();
    }
  • DetailPage의 showDialog 수정
    // 확인 버튼
    TextButton(
    	onPressed: () {
    		memoService.deleteMemo(index: index);
    		Navigator.pop(context);	// 팝업 닫기
    		Navigator.pop(context);	// HomePage로 가기
    		},
    	...
    )

함수 분리

  • Extract Method
    • Future은 void로 변경, return 삭제

0개의 댓글