0

How to display users based on category? I have never done this. What is the logic behind this to implement

Here is my AllUsersProvider class:

class AllUsersProvider extends ChangeNotifier {
  bool isLoading = false;
  List<UsersData>? userData = [];
  Future<void> getAllUsers(BuildContext context) async {
    isLoading = true;
    notifyListeners();
    try {
      bool isConnected = await NetworkHelper.checkInternet();
      if (!isConnected) {
        ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("Kindly Connect to internet")));
      } else {
        final response = await ApiService.getUsers();
        isLoading = false;
        notifyListeners();
        if (response.statusCode == 200) {
          final jsonResponse = json.decode(response.body);
          if (jsonResponse.containsKey("success")) {
            if (jsonResponse["success"]) {
              UsersModel usersModel = UsersModel.fromJson(jsonResponse);
              userData = usersModel.data;
              notifyListeners();
            }
          }
        } else {
          ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("Something went wrong")));
        }
      }
    } catch (error) {
      print(error);
      isLoading = false;
      notifyListeners();
    }
  }
}

And here I want to display users based on category

class UsersCategory extends StatefulWidget {
  final int categoryId;
  final List<HomeCategory>? categories;
  const UsersCategory({Key? key, required this.categoryId, required this.categories}) : super(key: key);

  @override
  State<UsersCategory> createState() => _UsersCategoryState();
}

class _UsersCategoryState extends State<UsersCategory> {
  
  late int _categoryId;
  @override
  void initState() {
    super.initState();
    _categoryId = widget.categoryId;
    Provider.of<AllUsersProvider>(context, listen: false).getAllUsers(context);
  }

  void _updateCategoryId(int newCategoryId) {
    setState(() {
      _categoryId = newCategoryId;
    });
  }

  @override
  Widget build(BuildContext context) {
    print(widget.categoryId);
    return Scaffold(
      appBar: AppBar(
        title: const Text("Users Category"),
      ),
      body: Column(
        children: [
          const Text("Category"),
          const SizedBox(height: 15),
          SizedBox(
            width: double.infinity,
            height: 80,
            child: ListView.builder(
              physics: const BouncingScrollPhysics(),
              scrollDirection: Axis.horizontal,
              itemCount: widget.categories?.length ?? 0,
              itemBuilder: (context, index) => GestureDetector(
                onTap: () {
                  _updateCategoryId(widget.categories?[index].id ?? 0);
                },
                child: Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 8.0),
                  child: Column(
                    children: [
                      Container(
                        height: 50,
                        width: 50,
                        decoration: BoxDecoration(
                          boxShadow: <BoxShadow>[
                            BoxShadow(
                              color: Colors.black.withOpacity(0.5),
                              blurRadius: 10,
                              offset: const Offset(0.0, 5),
                            )
                          ],
                          borderRadius: BorderRadius.circular(10),
                          color: Colors.white,
                        ),
                        child: Image.network(
                          widget.categories?[index].photo.toString() ?? "",
                          fit: BoxFit.contain,
                        ),
                      ),
                      const SizedBox(height: 5),
                      Text(widget.categories?[index].enName.toString() ?? ""),
                    ],
                  ),
                ),
              ),
            ),
          ),
          const SizedBox(height: 15),
          ShowUsersBasedOnCategory(categoryId: _categoryId)
        ],
      ),
    );
  }
}

class ShowUsersBasedOnCategory extends StatefulWidget {
  final int categoryId;
  const ShowUsersBasedOnCategory({Key? key, required this.categoryId}) : super(key: key);

  @override
  State<ShowUsersBasedOnCategory> createState() => _ShowUsersBasedOnCategoryState();
}

class _ShowUsersBasedOnCategoryState extends State<ShowUsersBasedOnCategory> {
  @override
  Widget build(BuildContext context) {
    return Expanded(
      child: Consumer<AllUsersProvider>(builder: (context, provider, _) {
        List<UsersData>? users = provider.userData?.where((user) => user.categoryId == widget.categoryId).toList();
        if (provider.isLoading) {
          return const Center(
            child: CircularProgressIndicator(),
          );
        } else if (users == null || users.isEmpty) {
          return const Center(
            child: Text("No users found for this category"),
          );
        } else {
          return GridView.builder(
            itemCount: users.length,
            shrinkWrap: true,
            gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
              childAspectRatio: 7 / 5,
              crossAxisCount: 2,
              mainAxisSpacing: 15,
            ),
            itemBuilder: (context, index) => Padding(
              padding: const EdgeInsets.symmetric(horizontal: 10),
              child: Container(
                decoration: BoxDecoration(
                  color: Colors.purple,
                  borderRadius: BorderRadius.circular(10),
                ),
                child: Center(child: Text(users[index].firstName.toString())),
              ),
            ),
          );
        }
      }),
    );
  }
}

When i click on category i also face this error

setState() or markNeedsBuild() called during build.

This _InheritedProviderScope<AllUsersProvider?> widget cannot be marked as needing to build because the framework is already in the process of building widgets. A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase.
The widget on which setState() or markNeedsBuild() was called was: _InheritedProviderScope<AllUsersProvider?>
  value: Instance of 'AllUsersProvider'
  listening to value
The widget which was currently being built when the offending call was made was: Builder
When the exception was thrown, this was the stack: 
#0      Element.markNeedsBuild.<anonymous closure> (package:flutter/src/widgets/framework.dart:4634:9)
#1      Element.markNeedsBuild (package:flutter/src/widgets/framework.dart:4646:6)
#2      _InheritedProviderScopeElement.markNeedsNotifyDependents (package:provider/src/inherited_provider.dart:577:5)
#3      ChangeNotifier.notifyListeners (package:flutter/src/foundation/change_notifier.dart:381:24)
#4      AllUsersProvider.getAllUsers (package:chatgpt_pracrtce/providers/all_users_provider.dart:14:5)
#5      _UsersCategoryState.didChangeDependencies (package:chatgpt_pracrtce/screens/users/users_category.dart:50:59)
#6      StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:5119:11)
#7      ComponentElement.mount (package:flutter/src/widgets/framework.dart:4944:5)
...     Normal element mounting (214 frames)
#221    Element.inflateWidget (package:flutter/src/widgets/framework.dart:3953:16)
#222    MultiChildRenderObjectElement.inflateWidget (package:flutter/src/widgets/framework.dart:6512:36)
#223    Element.updateChild (package:flutter/src/widgets/framework.dart:3682:18)
#224    RenderObjectElement.updateChildren (package:flutter/src/widgets/framework.dart:6041:32)
#225    MultiChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6537:17)
#226    Element.updateChild (package:flutter/src/widgets/framework.dart:3660:15)
#227    ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4993:16)
#228    StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:5133:11)
James Z
  • 12,209
  • 10
  • 24
  • 44
For Stack
  • 165
  • 15
  • That's a lot of code. I don't think people would want to read that. You should be straight to the point. Tell us exactly what you want to do with providers and what you have tried – Noah Feb 15 '23 at 10:22
  • I only want to display users based on category but when i click on category i get error `setState() or markNeedsBuild() called during build` – For Stack Feb 15 '23 at 10:25
  • Try this answer: https://stackoverflow.com/questions/47592301/setstate-or-markneedsbuild-called-during-build – Noah Feb 15 '23 at 10:25
  • I'm new in flutter bro, kindly can you point out issue in my code. – For Stack Feb 15 '23 at 10:27
  • I've checked this answer but didn't get it – For Stack Feb 15 '23 at 10:27
  • Remove this line `Provider.of(context, listen: false).getAllUsers(context);` and put it inside the build method instead – Noah Feb 15 '23 at 11:26
  • Are you sure `List? users = provider.userData?.where((user) => user.categoryId == widget.categoryId).toList();` is correct? Seems wrong to me – Noah Feb 15 '23 at 11:29

1 Answers1

0

An error you described in your question is comes because you've initialize your user array from provider during widget building process, for immediate widget or array filter updation you need to use value notifier. And make sure to avoid using setState cause it slower down your application it indirectly rebuild all widgets exists on class

Starts using value notifier to achiev this,

class ….{

ValueNotifier<int> varCategoryId = ValueNotifier(-1);


@override
void initState() {
  super.initState();

  varCategoryId.value = widget.categoryId;
  varCategoryId.notifyListeners();

}

When you click on particular category set below code,

onTap: () {

     varCategoryId.value = widget.categories?[index].id ?? 0;
     varCategoryId.notifyListeners();

},

& for user update wrap code within ValueListenableBuilder,

Replace your line,

ShowUsersBasedOnCategory(categoryId: _categoryId)

with

ValueListenableBuilder(
  valueListenable: varCategoryId,
  builder: (context, _varCategoryId, child){

    List<UsersData>? users = provider.userData?.where((user) => user.categoryId == _varCategoryId).toList();

    return Expanded(
      child: GridView.builder(
            itemCount: users.length,
            shrinkWrap: true,
            gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
              childAspectRatio: 7 / 5,
              crossAxisCount: 2,
              mainAxisSpacing: 15,
            ),
            itemBuilder: (context, index) => Padding(
              padding: const EdgeInsets.symmetric(horizontal: 10),
              child: Container(
                decoration: BoxDecoration(
                  color: Colors.purple,
                  borderRadius: BorderRadius.circular(10),
                ),
                child: Center(child: Text(users[index].firstName.toString())),
              ),
            ),
          ),
    );
  }
),
Dharini
  • 700
  • 7
  • 20