This is the 23rd day of my participation in the August More Text Challenge
preface
In the previous two articles, we had a basic understanding of the basic use of Redux and middleware. In this article, we will explore how to implement multi-component sharing of state data. Similar to providers, data can only be shared if the components are subordinate to the same parent.
Page structure
Our page structure is divided into three parts, corresponding to three components:
- Shopping list: support to select or cancel the selection of a single item, indicating whether the item has been purchased;
- New shopping item pop-up: Click ok to add new items to the list;
- Bottom shopping list statistics: indicates the progress of the current shopping list.
The interface is shown in the figure below. The three components in the interface are independent of each other, but they all need the same state data, that is, the shopping list.
The interface building code is not posted here, you can download the source code here: Redux state management source code.
State is shared between components
The three components above are not really related, so state needs to be defined on the common parent component of the three components. There is a special component here which is the add shopping item dialog popup. The call method is:
void _openAddItemDialog(BuildContext context) {
showDialog(context: context, builder: (context) => AddItemDialog());
}
Copy the code
The showDialog method here actually pops up a new page, which results in a dialog box that is not a child of any component other than the MaterialApp. Therefore, the definition of the state needs to be referred to the top level, which is placed above the MaterialApp, as shown below. This allows all components of the application to share state management.
class MainApp extends StatelessWidget {
MainApp({Key? key}) : super(key: key);
final store = Store<ShoppingListState>(
shoppingListReducer,
initialState: ShoppingListState.initial(),
);
@override
Widget build(BuildContext context) {
return StoreProvider(
store: store,
child: MaterialApp(
title: 'Redux Counter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: ShoppingListHome(), builder: EasyLoading.init(), ), ); }}Copy the code
The core business
The actual business component is ShoppingListHome:
class ShoppingListHome extends StatelessWidget {
const ShoppingListHome({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Shopping list'),
),
body: StoreConnector<ShoppingListState, List<Widget>>( converter: (store) => _ShoppListViewModel.build(store), builder: (context, items) => ListView.builder( itemBuilder: (context, index) => items[index], itemCount: items.length, ), ), bottomSheet: _BottomStatisticBar(), floatingActionButton: FloatingActionButton( child: Icon(Icons.add), onPressed: () => _openAddItemDialog(context), ), ); }}Copy the code
Core business is divided into four parts:
- The listing shows: it is used here
StoreConnector
Pass the list of states directlyconverter
Convert to a list of components to display, like thisListView.builder
It can be used directly. - Bottom statistics: Bottom statistics read the number of selected entries in the status list, also converted by Converter.
class _BottomStatisticBar extends StatelessWidget {
const _BottomStatisticBar({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return StoreConnector<ShoppingListState, int>(
builder: (context, selectedCount) => Container(
height: 60,
width: double.infinity,
color: Colors.grey,
padding: EdgeInsets.all(10),
child: Text('has been completed$selectedCountItem '), ), converter: (store) => store.state.shoppingItems.where((item) => item.selected).length, ); }}Copy the code
- Check box Select or deselect: You only need to pass
store
Initiating a state changeToggleItemStateAction
.
// ...Checkbox( value: item.selected, onChanged: (value) { store.dispatch(ToggleItemStateAction(item: item)); },),/ /...
Copy the code
- Add new shopping item: here we pass
converter
Converts the state to a callback function that can be used to initiate a callback after the dialog box clicks the Add button.
class AddItemDialog extends StatelessWidget {
@override
Widget build(BuildContext context) {
return StoreConnector<ShoppingListState, OnItemAddedCallback>(
converter: (store) {
return (itemName) => store.dispatch(
AddItemAction(
item: ShoppingItem(
name: itemName,
selected: false,))); }, builder: (context, callback) {return_AddItemDialogWidget(callback); }); }}Copy the code
As you can see from these businesses, Converter has a very flexible way of converting states into viewmodels based on what elements we need in the interface, thus simplifying our viewmodel construction.
The results
The result is shown in the figure below, where we find that if two shopping items have the same name, the checkbox selection will be problematic, when in fact, we can increase the number of items adding the same option. In the next article, we will make further improvements to this application, such as quantity display issues and offline storage, to achieve a relatively complete application example of Redux.
conclusion
This article shows how to build a Store on a top-level component that enables multiple components to share the state of Redux. Components in the same component tree can share state in this way. At the same time, the Converter parameters of StoreConnector can be flexibly used in actual development, which can simplify the construction of the interface.
This is a column about the entry and practice of Flutter. The corresponding source code is here: Entry and Practice of Flutter.
👍🏻 : feel the harvest please point a praise to encourage!
🌟 : Collect articles, easy to look back!
💬 : Comment exchange, mutual progress!