At the moment, the CoursesPage and FilterPage each separately maintain the state of the filter in the app. Now that you have an InheritedWidget in FilterStateContainer, you can replace the separate state on the two pages with the single state that is lifted up in the widget tree. In Flutter, this is referred to lifting state up.
You’ll make FilterStateContainer the parent of your MaterialApp, so that state is lifted up sufficiently highly to be used by both CoursesPage and FilterPage.
To get started, open your project in progress or download the sample project for this episode. In the UI and filter folder, open up the filter_page.dart.
In the last episode, we created a filter state. Instead of the state being private, we actually made it public. Replace the filterValue property with the state.
late FilterState state;
Naturally, we have to import the FilterObject.
import '../../state/filter_state_container.dart';
Since we don’t have filterValue, remove both the initState and loadValue methods. Of course, we still have lots of compile errors because our group value referred to the filterValue. Thankfully, we added a filterValue to our state object.
groupValue: state.filterValue,
We now need to update _handleRadioValueChange to just call updateFilterValue on the state object.
void _handleRadioValueChange(int value) async {
state.updateFilterValue(value ?? 0);
}
Now that we removed shared preferences from this widget, we can get rid of the import.
remove import
To set the value of the state property, add a method override in FilterPageState for its didChangeDependencies method.
class _FilterPageState extends State<FilterPage> {
late FilterState state;
@override
void didChangeDependencies() {
super.didChangeDependencies();
state = FilterStateContainer.of(context);
}
By setting the state property to the FilterStateContainer value, whenever the inherited widget is updated, so long as it’s updateShouldNotify returns true, the state property of FilterPageState will be updated as well, and the page will be rebuilt.
Now we make similar changes in CoursesPage. In the ui and courses subfolder, open up courses_page.dart. Now replace the filterValue with our state object.
late FilterState state;
Of course, make sure to import filter_state_container.dart.
import '../../state/filter_state_container.dart';
Now remove both of the initState and loadValue methods. With those methods gone, we can also remove the shared preferences and constants imports. We still have a compile error. Change build method so that the call to fetchCourses uses the state filterValue.
future: _controller.fetchCourses(state.filterValue),
We also want to update the check on a null course to check the snapshot connectedState property and continue to show a progress indicator if the connectionState is not done.
final courses = snapshot.data;
if (courses == null ||
(snapshot.connectionState != ConnectionState.done)) {
That way, when we refresh the filter, the progress indicator will be shown as the filter is applied. We need to add the same didChangeDependencies method override as we did for FilterPage.
final _controller = CoursesController(CourseRepository());
@override
void didChangeDependencies() {
super.didChangeDependencies();
state = FilterStateContainer.of(context);
}
Finally, we need to make our FilterStateContainer wrap the MaterialApp widget in main.dart.
void main() => runApp(
FilterStateContainer(
child: MaterialApp(
title: Strings.appTitle,
theme: ThemeData(primaryColor: Colors.green.shade800),
home: const RWCoursesApp(),
),
),
);
Believe it or not, that’s all there is to it. Let’s see this in action. Build and run the app. Navigate to filter and change it again. Go back. Navigate to filter and change it again. Everything is working great. Well done!