ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • bloc 중첩 사용해서 일부만 랜더링 시키기
    FLUTTER/Bloc 2023. 10. 9. 11:33

    BLoC 패턴

    [https://blog.arong.info/flutter/2023/01/10/Flutter-BLoC-%ED%8C%A8%ED%84%B4-1.html]
    블록 관련해서는 밍님의 위 시리즈를 보시면 매우 정리가 잘되어있습니다.

     

    bloc 패키지의 사용상 요점은 스테이트별로 클래스를 만들고 특정뷰에서 사용되는 블록/큐빗을 통해서 emit될때 스테이터스의 변경사항을 view에 적용하는 것이 핵심입니다.

     

    개발중 커스텀카드를 이용해 리스트빌더를 카드의 favorite icon을 클릭하면 favorite상태를 변경시키고 다시 리스트를 favorite 한 항목에 대해서 다시그려줘야 하는데 페이지별로 cubit을 사용하게되면 페이지 전체를 다시랜더링 해야하므로 낭비라고 생각하게 되었습니다.

     

    따라서 리스트빌더 부분만 다시그려주려고 하려보니

    1. 카드부분을 statefulwidget으로 만들기
    2. page cubit과 listbuilder cubit으로 나누어 사용하기

    쉽게하려면 statefullwidget을 사용하면 쉽게 상태를 변화시킬수 있을듯 했지만, bloc내에서 왠만하면 처리하고 stateful widget의 사용은 최소화하고 싶은 욕심이 있어서 2번으로 진행 하였습니다.

     

    다음은 Todo app을 만들어 작성한 위2번 방법의 샘플코드 입니다.

    // todo_page_cubit.dart
    import 'package:flutter_bloc/flutter_bloc.dart';
    
    enum PageStatus { unloaded, loaded }
    
    class TodoPageCubit extends Cubit<PageStatus> {
      TodoPageCubit() : super(PageStatus.unloaded);
    
      void loadPage() => emit(PageStatus.loaded);
    }
    // todo_list_cubit.dart
    import 'package:flutter_bloc/flutter_bloc.dart';
    
    class TodoListCubit extends Cubit<List<String>> {
      TodoListCubit() : super([]);
    
      void add(String task) {
        final updatedTodos = List<String>.from(state)..add(task);
        emit(updatedTodos);
      }
    
      void remove(int index) {
        final updatedTodos = List<String>.from(state)..removeAt(index);
        emit(updatedTodos);
      }
    }
    // ...
    
    class TodoPage extends StatelessWidget {
      final TextEditingController _controller = TextEditingController();
    
      @override
      Widget build(BuildContext context) {
        return BlocBuilder<TodoPageCubit, PageStatus>(
          builder: (context, pageStatus) {
            if (pageStatus == PageStatus.unloaded) {
              return Center(
                child: ElevatedButton(
                  onPressed: () => context.read<TodoPageCubit>().loadPage(),
                  child: Text('Load Page'),
                ),
              );
            }
    
            return Scaffold(
              appBar: AppBar(title: Text('Cubit Todo List')),
              body: Column(
                children: [
                  Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: TextField(
                      controller: _controller,
                      decoration: InputDecoration(
                        labelText: 'Enter task',
                        suffixIcon: IconButton(
                          icon: Icon(Icons.add),
                          onPressed: () {
                            if (_controller.text.isNotEmpty) {
                              context.read<TodoListCubit>().add(_controller.text);
                              _controller.clear();
                            }
                          },
                        ),
                      ),
                    ),
                  ),
                  Expanded(
                    child: BlocBuilder<TodoListCubit, List<String>>(
                      builder: (context, todos) {
                        return ListView.builder(
                          itemCount: todos.length,
                          itemBuilder: (context, index) {
                            return ListTile(
                              title: Text(todos[index]),
                              trailing: IconButton(
                                icon: Icon(Icons.delete),
                                onPressed: () {
                                  context.read<TodoListCubit>().remove(index);
                                },
                              ),
                            );
                          },
                        );
                      },
                    ),
                  ),
                ],
              ),
            );
          },
        );
      }
    }
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Cubit Todo List',
          theme: ThemeData(primarySwatch: Colors.blue),
          home: MultiBlocProvider(
            providers: [
              BlocProvider(create: (context) => TodoPageCubit()),
              BlocProvider(create: (context) => TodoListCubit()),
            ],
            child: TodoPage(),
          ),
        );
      }
    }

    flutter_bloc 8.1.3 버전만 사용되었습니다.

Designed by Tistory.