Итак, я реализовал архитектуру, показанную ResoCoder на YouTube в этой статье: https://resocoder.com/2020/12/11/flutter-statenotifier-riverpod-tutorial-immutable-state-management/#t-1607415476843.
У меня есть некоторые проблемы с пониманием того, как лучше всего инициализировать будущие данные по его схеме.
Скажем, у меня есть фиктивный Repository класс:
abstract class WeatherRepository {
Future<Weather> fetchWeather(String cityName);
}
class FakeWeatherRepository implements WeatherRepository {
double cachedTempCelsius;
@override
Future<Weather> fetchWeather(String cityName) {
// Simulate network delay
return Future.delayed(
Duration(seconds: 1),
() {
final random = Random();
// Simulate some network exception
if (random.nextBool()) {
throw NetworkException();
}
// Since we're inside a fake repository, we need to cache the temperature
// in order to have the same one returned in for the detailed weather
cachedTempCelsius = 20 + random.nextInt(15) + random.nextDouble();
// Return "fetched" weather
return Weather(
cityName: cityName,
// Temperature between 20 and 35.99
temperatureCelsius: cachedTempCelsius,
);
},
);
}
}
class NetworkException implements Exception {}
WeatherState класс:
abstract class WeatherState {
const WeatherState();
}
class WeatherInitial extends WeatherState {
const WeatherInitial();
}
class WeatherLoading extends WeatherState {
const WeatherLoading();
}
class WeatherLoaded extends WeatherState {
final Weather weather;
const WeatherLoaded(this.weather);
}
class WeatherError extends WeatherState {
final String message;
const WeatherError(this.message);
}
WeatherNotifier:
class WeatherNotifier extends StateNotifier<WeatherState> {
final WeatherRepository _weatherRepository;
WeatherNotifier(this._weatherRepository) : super(WeatherInitial());
Future<void> getWeather(String cityName) async {
try {
state = WeatherLoading();
final weather = await _weatherRepository.fetchWeather(cityName);
state = WeatherLoaded(weather);
} on NetworkException {
state = WeatherError("Couldn't fetch weather. Is the device online?");
}
}
}
Оба провайдера:
final weatherRepositoryProvider = Provider<WeatherRepository>(
(ref) => FakeWeatherRepository(),
);
final weatherNotifierProvider = StateNotifierProvider(
(ref) => WeatherNotifier(ref.watch(weatherRepositoryProvider)),
);
И WeatherSearchPage (UI):
...
child: Consumer(
builder: (context, watch, child) {
final state = watch(weatherNotifierProvider.state);
if (state is WeatherInitial) {
return buildInitialInput();
} else if (state is WeatherLoading) {
return buildLoading();
} else if (state is WeatherLoaded) {
return buildColumnWithData(state.weather);
} else {
// (state is WeatherError)
return buildInitialInput();
}
},
),
...
куда
Widget buildInitialInput() {
return Center(
child: CityInputField(), // builds a textfield to fetch the weather of some city
);
}
а также
Widget buildLoading() {
return Center(
child: CircularProgressIndicator(),
);
}
Column buildColumnWithData(Weather weather) {
return Column(
...
//shows data
...
);
}
Если мне нужно будет получить погоду в городе по умолчанию при создании страницы, где я должен назвать это, следуя этой логике?
Я попытался преобразовать WeatherSearchPage (UI) в виджет с отслеживанием состояния и вызвать в initState вот так
@override
void initState() {
context.read(weatherNotifierProvider).getWeather("Siena");
super.initState();
}
который работает, но кажется не очень чистым и не использует InitialState виджета. Какие-либо предложения?
Спасибо!