所以我在这篇文章中实现了 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 {}
天气状态类:
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);
}
天气通知器:
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。有什么建议么?
谢谢!