Home > Software engineering >  Call setState from class that extends StatefulWidget
Call setState from class that extends StatefulWidget

Time:03-31

If I update a variable using class object, the build method should get called, but I am unable to call setState from the StatefulWidget class.

class CustomErrorFormField extends StatefulWidget {

  @override
  _CustomErrorFormFieldState createState() {
    return _CustomErrorFormFieldState();
  }

  List<String> errorList = []; //this variable will get updated using below function
    
  void setErrorList(List<String> listOfError) {
        errorList = listOfError;
   }

}
class _CustomErrorFormFieldState extends State<CustomErrorFormField> {


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


 @override
 Widget build(BuildContext context) {

    print(widget.errorList); //this is not printing updated value

    return .....
  }
}

Now in some other class i will update errorList Variable

 nameTextFild = CustomErrorFormField(
       key: ValueKey(count),
      labelName: "Name",
      iContext: context,
      onChanged: (String value) {


        setState(() {
          count  ;
          if (!value.contains(RegExp(r'[0-9]'))) {
            nameTextFild!.setErrorList([]); //updating but changes not appearing (setState of this widget is not getting called)
          } else {
            nameTextFild!.setErrorList(["Invalid characters, use letters only."]);
          }

        });



      },
    );

CodePudding user response:

It's not recommended that you change the state of a widget from outside the widget.

What you should do instead is pass the validation logic as a function and let the widget handle the state change.

CustomFormField:

import 'package:flutter/material.dart';

class CustomErrorFormField extends StatefulWidget {
  //Take the validation logic as a parameter.
  final List<String> Function(String value) validator;
  const CustomErrorFormField({required this.validator});

  @override
  _CustomErrorFormFieldState createState() {
    return _CustomErrorFormFieldState();
  }
}

class _CustomErrorFormFieldState extends State<CustomErrorFormField> {
  
  //Keep the state inside the widget itself
  List<String> errorList = [];

  //Update the state from inside the widget
  void setErrorList(List<String> listOfError) {
    setState(() {
      errorList = listOfError;
    });
  }

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

  @override
  Widget build(BuildContext context) {
    return Form(
      child: TextFormField(
        validator: (String value){
           //Use the validation logic to decide the error.
           setErrorList(widget.validator(value))
          }
        }
      ),
    );
  }
}

I have used TextFormField as an example, you can use any widget that accepts a callback upon change.

If you're making everything from scratch you can attach the validator function to a callback that fires when the text is changed. Usually this is done with the help of a controller.

usage:

final nameTextFild = CustomErrorFormField(
  key: ValueKey(count),
  labelName: "Name",
  iContext: context,
  validator: (String value) {
    if (!value.contains(RegExp(r'[0-9]'))) {
      return [];
    } else {
      return ["Invalid characters, use letters only."];
    }
  },
);
  • Related