Я хотел бы научиться пользоваться Riverpod, поэтому для этой цели я реализую небольшое приложение, которое показывает список элементов и кнопку, которая добавляет фиктивный элемент в список при нажатии.
Нажатие кнопки в следующем приложении работает должным образом (добавляется фиктивный элемент, и изменение немедленно отражается в пользовательском интерфейсе):
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
void main() => runApp(const ProviderScope(child: MyApp()));
class MyApp extends StatelessWidget {
const MyApp({Key key}) : super(key: key);
@override
Widget build(BuildContext context) => MaterialApp(home: HomePage());
}
final itemsProvider = StateNotifierProvider((ref) => ItemsList());
class ItemsList extends StateNotifier<List<String>> {
ItemsList([List<String> items]) : super(items ?? []);
void add(String item) => state = [...state, item];
}
class HomePage extends ConsumerWidget {
const HomePage({Key key}) : super(key: key);
@override
Widget build(BuildContext context, ScopedReader watch) {
final items = watch(itemsProvider.state);
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: items.map((e) => Text(e)).toList(),
),
floatingActionButton: FloatingActionButton(
onPressed: () => context.read(itemsProvider).add('Other item'),
tooltip: 'Add item',
child: Icon(Icons.add),
),
);
}
}
Внутри метода add
класса ItemsList
я думал, что изменение оператора state = [...state, item]
на state.add(item)
не будет иметь никакого значения. Однако при этом приложение больше не реагирует на изменения состояния: нажатие кнопки не приводит к изменению пользовательского интерфейса, и я не вижу никаких новых элементов в пользовательском интерфейсе, пока не перезагружу свое приложение в горячем режиме.
Так что просто для ясности: изменение void add(String item) => state = [...state, item];
на void add(String item) => state.add(item);
разрывает связь между состоянием приложения и пользовательским интерфейсом.
Почему ручное добавление элемента с деструктурированием списка отличается от использования List.add
? Заранее большое спасибо.
Состояние должно измениться так, чтобы oldValue == newValue
было ложным. И по умолчанию добавление элементов в список с помощью .add
изменяет список на месте, поэтому равенство сохраняется. Вот почему во всех примерах есть что-то вроде state = [...state, foo]
, так что в состоянии находится совершенно новый список, который не равен старому списку.
Ничего не исправить. Он работает, как задумано. И если вы используете новых провайдеров (а не провайдеров версии до 2.0), вы можете вызывать ref.notifyListeners()
даже после того, как ваш метод mutate уже изменил состояние, как это было бы необходимо для ChangeNotifier.
это должно быть что-то вроде .refresh(), если есть очень большой список, который будет копироваться в следующий каждый раз, когда это не оптимально для производительности, надеюсь, что в будущем это будет исправлено.