Search code examples
listflutterdartsocket.iosetstate

cant update listview with socket.io data in flutter?


I am developing a backend using node.js and express and MongoDB and socket.io and in the front-end, I am using flutter and dart.

I am using emit to emit data from backend to the flutter app and it works fine and I can receive the message so the problem isn't in the backend.

when I receive that message I want to add it to a list and then setstate to refresh the build method to rebuild the build method but it fails and gives me that error:

[ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: setState() called after dispose(): _NewsState#a696c(lifecycle state: defunct, not mounted)
E/flutter (11883): This error happens if you call setState() on a State object for a widget that no longer appears in the widget tree (e.g., whose parent widget no longer includes the widget in its build). This error can occur when code calls setState() from a timer or an animation callback.
E/flutter (11883): The preferred solution is to cancel the timer or stop listening to the animation in the dispose() callback. Another solution is to check the "mounted" property of this object before calling setState() to ensure the object is still in the tree.
E/flutter (11883): This error might indicate a memory leak if setState() is being called because another object is retaining a reference to this State object after it has been removed from the tree. To avoid memory leaks, consider breaking the reference to this object during dispose().

here is my code snippet to listen to events coming from backend:

Provider.of<IoProvider>(context).globalSocket.connect();
    Provider.of<IoProvider>(context).globalSocket.on('posts', (data) {
      if (data['action'] == 'add') {
        setState(() {
          postData.add(data['data']);
        });
      }
      print('--emit--');
    });

I am using this in the build method and I have declared the postData list at the top of the state class.

I am also using a future function inside the init state method to get the data from the backend and then setstate to make postData equal to the response data coming from the backend and its a success.

code snippet:

Future getPosts() async {
    var data = await PostController().fetchPosts();

    if (data['success'] == true) {
      setState(() {
        postData = data['posts'];
      });
    }
  }

inside the initState:

@override
  void initState() {
    super.initState();
    Future.delayed(Duration.zero, () {
      getPosts(context);
    });
      _editingController = TextEditingController();
  }

inside build method:

ListView.builder(
    itemCount: postData.length,
    itemBuilder: (context , index) => PostView(postData[index]),
  );

Update

after testing I found that the problem not happening in the first time a user navigates to that screen but in the other times it fails.

but how to solve it?


Solution

  • After too much searching, I figured out the problem is occurred by flutter itself as I was using a bottom navigation bar with four screens and they recall initstate each time I go to them after some time.

    finally, I was able to solve this problem by using the indexed stack widget.

    Thank you,