오늘은 기존 코딩을 StateNotifierProvider 로 변경해보겠습니다.
개발환경 : 윈도우11, 안드로이드 스튜디오, flutter 2.10.3
소스코드 위치 - 09_StateNotifierProvider · mike-bskim/todo_test · GitHub
수정 대상은
todo_filter.dart
todo_search.dart
todo_list.dart
todo_active_count.dart
filtered_todos.dart
main.dart
todos_screen.dart
todo_filter.dart - 주요 수정부분만 표시함
class TodoFilter extends StateNotifier<TodoFilterState> {
// 상태를 가지고 있으므로 기존에 사용하던 state 변수는 모두 제거
// TodoFilterState _state = ;
// TodoFilterState get state => _state;
TodoFilter() : super(TodoFilterState.init());
void changeFilter(Filter newFilter) {
state = state.copyWith(filter: newFilter);
// notifyListeners(); // 이것도 이제는 필요없음
}
}
todo_search.dart - 주요 수정부분만 표시함
class TodoSearch extends StateNotifier<TodoSearchState> {
// TodoSearchState _state = TodoSearchState.init();
// TodoSearchState get state => _state;
TodoSearch() : super(TodoSearchState.init());
void setSearchTerm(String newSearchTerm) {
state = state.copyWith(searchTerm: newSearchTerm);
// notifyListeners();
}
}
todo_list.dart - 주요 수정부분만 표시함
class TodoList extends StateNotifier<TodoListState> {
// TodoListState _state = TodoListState.init();
// TodoListState get state => _state;
TodoList() : super(TodoListState.init());
// 리스트 추가
void addTodo(String todoDesc) {
int? newNum;
if (state.todos.isEmpty) {
newNum = 1;
} else {
// 마지막 id 에서 1 증가
newNum = int.parse(state.todos.last.id) + 1;
}
final newTodo = Todo(id: newNum.toString(), desc: todoDesc);
final newTodos = [...state.todos, newTodo];
// 리스트 새로 복사&생성
state = state.copyWith(todos: newTodos);
debugPrint('addTodo: ' + state.toString());
// notifyListeners();
}
void editTodo(String id, String desc) {
final newTodos = state.todos.map((Todo todo) {
if (todo.id == id) {
return Todo(
id: id,
desc: desc,
completed: todo.completed,
);
}
return todo;
}).toList();
state = state.copyWith(todos: newTodos);
// notifyListeners();
}
void removeTodo(String id) {
final newTodos = state.todos.where((Todo todo) => todo.id != id).toList();
state = state.copyWith(todos: newTodos);
debugPrint('remove Todos: ' + state.toString());
// notifyListeners();
}
void toggleTodo(String id) {
final newTodos = state.todos.map((Todo todo) {
// 해당 리스트만 토글
if (todo.id == id) {
return Todo(
id: id,
desc: todo.desc,
completed: !todo.completed,
);
}
// 다른 리스트는 그대로 리턴
return todo;
}).toList();
// 토글된 리스트 새로 복사&생성
state = state.copyWith(todos: newTodos);
// notifyListeners();
}
}
todo_active_count.dart - 주요 수정부분만 표시함
// ProxyProvider 구현 부분은 StateNotifier 로 변경, 제네릭지정 필요함
// 'with LocatorMixin' 구문으로 다른 Provider 의 상태를 직접 접근가능
class TodoActiveCount extends StateNotifier<TodoActiveCountState>
with LocatorMixin {
// final TodoList todoList;
// TodoActiveCount({required this.todoList});
TodoActiveCount() : super(TodoActiveCountState.init());
@override
void update(Locator watch) {
// context 없이 직접 접근 가능함
// 기존에는 watch<TodoList>().state.todos 로 접근가능했으나
// 이제는 state 에 직접 접근 불가함
// 그래서 watch<TodoListState>().todos 이렇게 변경해야 함.
final List<Todo> todos = watch<TodoListState>().todos;
state = state.copyWith(
todoActiveCount:
todos.where((Todo todo) => !todo.completed).toList().length);
super.update(watch);
}
}
filtered_todos.dart - 주요 수정부분만 표시함
class FilteredTodos extends StateNotifier<FilteredTodosState>
with LocatorMixin {
FilteredTodos() : super(FilteredTodosState.initial());
@override
void update(Locator watch) {
// 다른 provider 의 상태값을 context 없이 직접 접근 가능함.
final Filter filter = watch<TodoFilterState>().filter;
final String searchTerm = watch<TodoSearchState>().searchTerm;
final List<Todo> todos = watch<TodoListState>().todos;
List<Todo> _filteredTodos;
// 핵심 부분. 필터의 조건에 맞는 리스트를 만드는 기능
switch (filter) {
case Filter.active:
_filteredTodos = todos.where((Todo todo) => !todo.completed).toList();
break;
case Filter.completed:
_filteredTodos = todos.where((Todo todo) => todo.completed).toList();
break;
case Filter.all:
default:
_filteredTodos = todos;
break;
}
// 로직 추가
if (searchTerm.isNotEmpty) {
_filteredTodos = _filteredTodos
.where((Todo todo) => todo.desc.toLowerCase().contains(searchTerm))
.toList();
}
state = state.copyWith(filteredTodos: _filteredTodos);
super.update(watch);
}
}
main.dart - 주요 수정부분만 표시함
return MultiProvider(
providers: [
StateNotifierProvider<TodoList, TodoListState>(
create: (context) => TodoList()),
StateNotifierProvider<TodoFilter, TodoFilterState>(
create: (context) => TodoFilter()),
StateNotifierProvider<TodoSearch, TodoSearchState>(
create: (context) => TodoSearch()),
StateNotifierProvider<TodoActiveCount, TodoActiveCountState>(
create: (context) => TodoActiveCount()),
StateNotifierProvider<FilteredTodos, FilteredTodosState>(
create: (context) => FilteredTodos()),
],
child: MaterialApp(
title: 'TODOS',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const TodosScreen(),
),
);
todos_screen.dart - 주요 수정부분만 표시함(watch 부분만 수정)
class TodoHeader extends StatelessWidget {
const TodoHeader({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
'TODO',
style: TextStyle(fontSize: 40.0),
),
Text(
// '${context.watch<TodoActiveCount>().state.todoActiveCount} items left',
// 제네릭은 TodoActiveCount --> TodoActiveCountState
// state 제거, .state.todoActiveCount --> .todoActiveCount
'${context.watch<TodoActiveCountState>().todoActiveCount} items left',
style: const TextStyle(
fontSize: 20.0,
color: Colors.redAccent,
),
),
],
);
}
}
Color textColor(BuildContext context, Filter filter) {
var currentFilter = context.watch<TodoFilterState>().filter;
return currentFilter == filter ? Colors.blueAccent : Colors.grey;
}
FontWeight textFontWeight(BuildContext context, Filter filter) {
var currentFilter = context.watch<TodoFilterState>().filter;
return currentFilter == filter ? FontWeight.bold : FontWeight.normal;
}
class ShowTodos extends StatelessWidget {
.....
@override
Widget build(BuildContext context) {
// final todos = context.watch<FilteredTodos>().state.filteredTodos;
final todos = context.watch<FilteredTodosState>().filteredTodos;
[참고자료] udemy - Flutter Provider Essential 코스 (Korean)
'Flutter > 10 app Todo with provider' 카테고리의 다른 글
[Flutter] App Todo(ChangeNotifierProxyProvider -> ProxyProvider) (0) | 2022.05.20 |
---|---|
[Flutter] App Todo(with Provider) - 6단계 리스트 삭제, 편집 (0) | 2022.05.20 |
[Flutter] App Todo(with Provider) - 5단계 할일 개수 표시 (0) | 2022.05.20 |
[Flutter] App Todo(with Provider) - 4단계 검색 (0) | 2022.05.20 |
[Flutter] App Todo(with Provider) - 3단계 필터 및 리스트, cascade notation (0) | 2022.05.18 |