[FLUTTER] 상태관리 응용 앱 제작 2 - InheritedWidget

2025. 1. 21. 10:14·Flutter

 

InheritedWidget

 Inherited Widget은 Flutter에서 상위 위젯에서 하위 위젯으로 데이터를 전달할 때 주로 이용됩니다.
위젯을 사용시 StatefulWidget과 StatelessWidget을 사용하여 트리가 구성이 될때 변화가 필요한 위젯이 트리의 마지막에 위치할 경우 타고 타고 올라가서 Top까지 올라가야 하지만 Inherited Widget을 사용하게 된다면 바로 Top에 접근이 가능해집니다.

그렇지만 서도 내려갈때는 트리의 중간 위젯을 거치기 때문에 build를  Inherited Widget부터 사용중인 위젯까지 전부 해주게 됩니다.

 

 

 

InheritedParent
// InheritedWidget 내장 데이터 타입을 상속받아 구현한다.
import 'package:flutter/cupertino.dart';
import '../common.utils/logger.dart';

class InheritedParent extends InheritedWidget {
  // 공유 상태 데이터 관리에 목적
  // List<String> mySelectedBooks = [];
  List<String> state; // 카드에 담긴 책 목록(공유 상태)
  // 부모에게 콜백 메서드를 관리하는 목적
  void Function(String book) onPressed; // 이벤트 핸들러

  // HOW <-- 사용방법
  // WHY <---
  InheritedParent({
    required this.state,
    required this.onPressed,
    required super.child,
  });

  // 상태가 변경되었는지 여부를 판단하는 메서드
  // 주의점 ! InheritedWidget --> 재정의 클래스를 InheritedParent 넣어 주자.

  // 메서드안 InheritedParent 타입 확인
  @override
  bool updateShouldNotify(covariant InheritedParent oldWidget) {
    logger.d('InheritedParent - updateShouldNotify() 호출 확인 ');

    // 상태가 달라졌다면 어떻게 판별할까?
    if (state.length != oldWidget.state.length) {
      logger.d('상태 변경 됨 ');
      return true;
    }

    for (int i = 0; i < state.length; i++) {
      // state --> String --> '호모사피엔스'
      // state[i] --> String ---> 호모사피엔스
      if (state[i] != oldWidget.state[i]) {
        return true;
      }
    }

    // 상태 변경이 없으면 false 를 반환하여 자식 위젯을 다시 빌드 않되도록 한다.
    return false; // 상태 변경 없음
  }
}

 

 

기존의 BookListPage에서 수정
  @override
  Widget build(BuildContext context) {
  
    // BuildContext 를 사용하여 우리가
    // 정의한 InheritedParent 위젯에 접근할 수 있다.
    InheritedParent? inheritedParent =
        context.dependOnInheritedWidgetOfExactType();

    // 공유 상태 데이터 -> 즉, 카트에 넣어둔 String 값을 가지고 와야 한다.
    List<String> selectedBook = inheritedParent?.state ?? [];

    return inheritedParent == null
        ? Center(child: Text('데이터가 없네요'))
        : ListView(
            children: books.map(
              // book <-- books 에 0인덱스는 '호모사피엔스';
              (book) {
                final isSelectedBook = selectedBook.contains(book);
                return ListTile(
                  leading: Container(
                    width: 35,
                    height: 35,
                    decoration: BoxDecoration(
                      color: Theme.of(context).secondaryHeaderColor,
                      borderRadius: BorderRadius.circular(8.0),
                      border: Border.all(color: Colors.black),
                    ),
                  ),
                  title: Text(
                    book,
                    style: TextStyle(fontSize: 12, fontWeight: FontWeight.bold),
                  ),
                  trailing: IconButton(
                    onPressed: () {
                      // 부모에게 콜백을 호출하는데 데이터도 함께 전달 시킨다.
                      inheritedParent.onPressed(book);
                      //onToggleSaved(book);
                    },
                    icon: Icon(
                      // isSelectedBook --> map 안에 지역 변수
                      isSelectedBook ? Icons.remove_circle : Icons.add_circle,
                      color: isSelectedBook ? Colors.red : Colors.green,
                    ),
                  ),
                );
              },
            ).toList(),
          );
  }
}

 

BookCartPage
import 'package:flutter/material.dart';
import 'package:flutter_statement_v01/_03/inherited_parent.dart';

class BookCartPage extends StatelessWidget {
  // 사용자가 카드에 저장한 데이터만 화면에 뿌려 주자.

  const BookCartPage({super.key});

  @override
  Widget build(BuildContext context) {
    InheritedParent inheritedParent =
        // ! 널이 절대 아님을 우리는 알고 있다.
        context.dependOnInheritedWidgetOfExactType<InheritedParent>()!;

    return ListView(
        children: inheritedParent.state
            .map((book) => ListTile(title: Text(book)))
            .toList());
  }
}

 

 

HomeScreen
import 'package:flutter/material.dart';
import '../common.utils/logger.dart';
import 'book_cart_page.dart';
import 'book_list_page.dart';
import 'inherited_parent.dart';

// 상태가 있는 위젯

class HomeScreen extends StatefulWidget {
  const HomeScreen({super.key});

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  // 로컬 상태 : 하단에 활동화 된 탭 인덱스 번호
  int pageIndex = 0;
  // 공유 상태  카드에 담긴 북 정보
  // (책 리스트 화면, 장바구니 화면에서 공유하는 데이터)
  // 상품 --> 책 (String) 데이터 타입으로 관리하자.
  List<String> mySelectedBook = [];

  // 상태를 변경하는 메서드 만들기
  void _toggleSaveStates(String book) {
    // 다시 화면을 그려라 요청 함수
    setState(() {
      if (mySelectedBook.contains(book)) {
        mySelectedBook.remove(book);
      } else {
        mySelectedBook.add(book);
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    logger.d('HomeScreen build 메서드 호출 됨');
    return SafeArea(
      child: Scaffold(
        appBar: AppBar(
          title: Text('텐코에 서재'),
          backgroundColor: Theme.of(context).colorScheme.tertiaryContainer,
        ),
        body: InheritedParent(
          state: mySelectedBook,
          onPressed: _toggleSaveStates,
          // super.child
          child: IndexedStack(
            // 반드시 추가해야 되는 속성
            index: pageIndex,
            children: [
              BookListPage(),
              BookCartPage(),
            ],
          ),
        ),
        bottomNavigationBar: BottomNavigationBar(
          // 필수 속성
          currentIndex: pageIndex,
          onTap: (index) {
            // 행위 .. 생략..
            setState(() {
              pageIndex = index;
            });
          },
          items: [
            BottomNavigationBarItem(
              icon: Icon(Icons.list),
              label: 'book-list',
            ),
            BottomNavigationBarItem(
              icon: Icon(Icons.shopping_cart),
              label: 'cart',
            ),
          ],
        ),
      ),
    );
  }
}

'Flutter' 카테고리의 다른 글

[FLUTTER] 상태관리 응용 앱 제작 1 - StatefulWidget  (2) 2025.01.20
[FLUTTER] 콜백 함수(Callback Function)  (0) 2025.01.20
[FLUTTER] Stack 위젯  (0) 2025.01.20
[FLUTTER] 기초 화면 구성  (0) 2025.01.20
[FLUTTER] 위젯(Widget)  (0) 2025.01.20
'Flutter' 카테고리의 다른 글
  • [FLUTTER] 상태관리 응용 앱 제작 1 - StatefulWidget
  • [FLUTTER] 콜백 함수(Callback Function)
  • [FLUTTER] Stack 위젯
  • [FLUTTER] 기초 화면 구성
noily4748
noily4748
백엔드 개발을 공부하고 있는 개발자 입니다!
  • noily4748
    noily4748 님의 블로그
    noily4748
  • 전체
    오늘
    어제
    • 분류 전체보기 (37)
      • 웹 (2)
      • Flutter (11)
      • Dart (5)
      • 디자인 패턴 (4)
      • 디스코드 (2)
      • [Flutter] 눈길 팀 프로젝트 (10)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
noily4748
[FLUTTER] 상태관리 응용 앱 제작 2 - InheritedWidget
상단으로

티스토리툴바