item property
Optimized for item displaying. Used with
Working with a list of items, we may want to display them using the
ListView
widget of Flutter. At this stage, we are faced with some
problems regarding :
- performance: Can we use the
const
constructor for the item widget. Then, how to update the item widget if the list of items updates. - Widget tree structure: What if the item widget is a big widget with its nested widget tree. Then, how to pass the state of the item through the widget three? Are we forced to pass it through a nest tree of constructors?
- State mutation: How to efficiently update the list of items when an item is updated.
InjectedCRUD, solves those problems using the concept of inherited injected. Injected.inherited
Example:
inherited
products.inherited({
required Key key,
required T Function()? item,
required Widget Function(BuildContext) builder,
String? debugPrintWhenNotifiedPreMessage,
})
Key is required here because we are dealing with a list of widgets with a similar state.
Example:
Widget build(BuildContext context) {
return OnReactive(
()=> ListView.builder(
itemCount: products.state.length,
itemBuilder: (context, index) {
//Put InheritedWidget here that holds the item state
return todos.item.inherited(
key: Key('${products.state[index].id}'),
item: () => products.state[index],
builder: (context) => const ProductItem(),//use of const
);
},
);
);
In the ListBuilder, we used the inherited
method to display the
ItemWidget
. This has huge advantages:
- As the
inherited
method inserts anInheritedWidget
aboveItemWidget
, we can take advantage of everything you know aboutInheritedWidget
. - Using const constructors for item widgets.
- Item widgets can be gigantic widgets with a long widget tree. We can easily get the state of an item and mutate it with the state of the original list of items even in the deepest widget.
- The
inherited
method, binds the item to the list of items so that updating an item updates the state of the list of items and sends an update request to the database. Likewise, updating the list of items will update theItemWidget
even if it is built with the const constructor.
call(context)
From a child of the item widget, we can obtain an injected state of the item using the call method:
Inherited<T> product = products.item.call(context);
//item is callable object. `call` can be removed
Inherited<T> product = products.item(context);
You can use the injected product to listen to and mutate the state.
product.state = updatedProduct;
Here we mutated the state of one item, the UI will update to display the new state, and, importantly, the list of items will update and update query with the default parameter is sent to the backend service.
Another important behavior is that if the list of items is updated, the item states will update and the Item Widget is re-rendered, even if it is declared with const constructor. (This is possible because of the underlying InheritedWidget).
of(context)
It is used to obtain the state of an item. The BuildContext
is
subscribed to the inherited widget used on top of the item widget,
T product = products.item.of(context);
of(context) vs call(context):
- of(context) gets the state of the item, whereas, call(context) gets the
Injected
object.
- of(context) subscribes the BuildContext to the InheritedWidget, whereas call(context) does not.
reInherited
As we know InheritedWidget
cannot cross route boundary unless it is
defined above the MaterielApp
widget (which s a nonpractical case).
After navigation, the BuildContext
connection loses the connection
with the InheritedWidgets
defined in the old route. To overcome this
shortcoming, with state_rebuilder, we can reinject the state to the next
route:
RM.navigate.to(
products.item.reInherited(
// Pass the current context
context : context,
// The builder method, Notice we can use const here, which is a big
// performance gain
builder: (BuildContext context)=> const NewItemDetailedWidget()
)
)
Implementation
late final _Item<T, P> item = _Item<T, P>(this as InjectedCRUDImp<T, P>);