How can I set the value of a variable before the buid method is called?

50 Views Asked by At

I have a simple statefullWidget like this:

class HomeScreen extends StatefulWidget {
  const HomeScreen({super.key});

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  late String _email;

  void getEmail() async {
    -> doing stuff and **set the value of _email**
  }

  @override
  void initState() {
    super.initState();
    getEmail(); //I invoke the method during the initstate()
  }

  @override
  Widget build(BuildContext context) {
    
    return Scaffold(
      body: SafeArea(
        child: Text(_email);
      ),
    );
  }
}

Doing this I get an exception saying me that the value of email is null. I thought that the method initState() was called before the build method, but maybe I am wrong.

Do you have and idea to how to solve my problem?

P.S. If I declare the variable _email like this:

String _email = '';

my UI starts with a blank space and then is filled with the correct value of the email. I don't want that, though.

3

There are 3 best solutions below

0
mashood touchworld On

In this modification, I introduced a separate method _initializeState that calls getEmail and then updates the state using setState only if the widget is still mounted. This ensures that the UI is updated only when the asynchronous operation is completed.

class HomeScreen extends StatefulWidget {
  const HomeScreen({super.key});

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  late String _email;

  Future<void> getEmail() async {
    // ... doing stuff and setting the value of _email
  }

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

  Future<void> _initializeState() async {
    await getEmail();
    if (mounted) {
      // Ensure the widget is still part of the widget tree.
      setState(() {
        // This will trigger a rebuild and update the UI with the correct email.
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Text(_email),
      ),
    );
  }
}
1
Vivek Chib On

Use a FutureBuilder if the getMail method takes some time:

return Scaffold(
    body: SafeArea(
      child: FutureBuilder(
        future: getEmail(), //Return type should be Future<String>
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting) {
            return const Center(child: CircularProgressIndicator());
          } else if (snapshot.hasError) {
            return Text(snapshot.error.toString());
          } else if (snapshot.hasData) {
            return Text(snapshot.hasData.toString());
          } else {
            return const Text('No data available');
          }
        },
      ),
    ),
  );
1
KlloShe On

Your logic is correct, but you need to add value in a simple way.

Try this:

void getEmail() async {
        -> doing stuff and **set the value of _email**
        _email = '[email protected]';
      }

.

  @override
  void initState() {
    getEmail(); //I invoke the method during the initstate()
    super.initState();      
}

if you want to get email from other Widget (other screen) you have to add Static member variables like this :

class HomeScreen extends StatefulWidget {
  const HomeScreen({super.key,required this.emailFromOtherScreen});


 ////////////////////////////////////////
    final String emailFromOtherScreen;
////////////////////////////////////////


  @override
      State<HomeScreen> createState() => _HomeScreenState();
    }

class _HomeScreenState extends State<HomeScreen> {
  late String _email;

  void getEmail() async {
    -> doing stuff and **set the value of _email**
   _email = widget.emailFromOtherScreen;
  }

  @override
  void initState() {
    super.initState();
    getEmail(); //I invoke the method during the initstate()
  }

  @override
  Widget build(BuildContext context) {
    
    return Scaffold(
      body: SafeArea(
        child: Text(_email);
      ),
    );
  }
}