flutterbookmarksfavoritesstatefulwidgetstatelesswidget

Pass variable from MaterialPageRoute to custom widget


A little bit of background: Flutter noob here, trying to build an Add To Favourites function. The list of items sits in a PHP/MySQL database which I access using http on FirstScreen. When user taps on one of the list items, they get redirected to SecondScreen and I pass the 'itemId' using MaterialPageRoute, which has an Add To Favourites button. The 'itemId' of favourited items are stored locally using sqflite. I can access 'itemId' using a StatefulWidget but I haven't been successful trying to create a custom Stateful widget that manages a Stateless Widget, like in this Flutter example on interactivity, i.e. I am unable to access 'itemId' from the custom Stateful widget.

Code snippet:

MaterialPageRoute(
  builder: (context) => SecondScreen(
  itemId: item[index].itemId,

My sqflite checkFavourited function:

Future<bool> checkFavourited(String itemId) async {
        Database db = await instance.database;
        var bookmarked = await db.query(table,
            where: 'itemId = ?',
            whereArgs: [itemId]);
        return bookmarked.isEmpty ? false : true;
      }

Working StatefulWidget:

 bool _isFavourited = false;

  void isFavourited() async {
    final isFavourited =
        await DatabaseHelper.instance.checkFavourited(widget.itemId);
    setState(() {
      _isFavourited = isFavourited;
    });
  }

But my attempts to do it in a StatelessWidget have failed. So far I have:

class SecondScreen extends StatelessWidget {
  final String itemId;
  SecondScreen({
    Key key,
    @required this.itemId,

I get the following error message:

The getter 'itemId' isn't defined for the type 'FavouritedButton'.

when I try to do this:

class FavouritedButton extends StatefulWidget {
  @override
  _FavouritedButtonState createState() => _FavouritedButtonState();
}

class _FavouritedButtonState extends State<FavouritedButton> {
  bool _isFavourited = false;

  void isFavourited() async {
    final isFavourited =
    await DatabaseHelper.instance.checkBookmark(widget.itemId);
    setState(() {
      _isFavourited = isFavourited;
    });
  }
  @override
  Widget build(BuildContext context) {
    return IconButton(
      icon: isFavourited
          ? Icon(Icons.bookmark)
          : Icon(
              Icons.bookmark_border,
            ),

I have read Flutter's Simple app state management and List of state management approaches articles and I might be wrong but is there be an easier solution than Provider or FutureBuilder?

I know this is a long post and will really appreciate if anyone can give me some pointers on this. Thanks in advance!


Solution

  • Clean code approach, by isolating your widget rebuild to be as narrow as possible, you are doing things right, but need to move id to your stateful widget.

    class FavouritedButton extends StatefulWidget {
    final String itemId;
      FavouritedButton({required this.itemId});
    
      @override
      _FavouritedButtonState createState() => _FavouritedButtonState();
    }
    class _FavouritedButtonState extends State<FavouritedButton> {
    //add initState here, and keep the rest of your widget as it is.
     @override
      void initState() {
      isFavourited();
        super.initState();
      }
    
    

    Then in your stateless widget:

    class SecondScreen extends StatelessWidget {
     final String itemId;
    
      const SecondScreen({Key? key, required this.itemId}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        
        return Column(children:[
         Text('write some text about your widget or $itemId'),
         FavouritedButton(itemId:itemId)
      ]);
      }
    }
    

    This will only rebuild your favorite button.