Joney Spark
Joney Spark

Reputation: 265

setState() or markNeedsBuild() called during build in Flutter

in my Todo App list, I'm trying to make the global state in my task list view but I'm facing some issues. I'm using StatefulWidget and StatelessWidget. In StatelessWidget Checkbox onChanged I want to toggle the Checkbox value and comes from the parent Widget but it's showing some setState() build issue Please have a look If you can.

tasks_lists.dart


import 'package:flutter/material.dart';

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

  @override
  State<TasksList> createState() => _TasksListState();
}

class _TasksListState extends State<TasksList> {
  bool isChecked = false;

  @override
  Widget build(BuildContext context) {
    return ListTile(
      title: Text(
        'List 1',
        style: TextStyle(
          color: Colors.black,
          decoration:
              isChecked ? TextDecoration.lineThrough : TextDecoration.none,
        ),
      ),
      trailing: TaskCheckbox(
        checkBoxState: isChecked,
        toggleCheckboxState: (bool checkedBoxState) {
          setState(
            () {
              isChecked = checkedBoxState;
            },
          );
        },
      ),
    );
  }
}

class TaskCheckbox extends StatelessWidget {
  final bool checkBoxState;
  final Function? toggleCheckboxState;

  const TaskCheckbox({
    super.key,
    required this.checkBoxState,
    this.toggleCheckboxState,
  });

  @override
  Widget build(BuildContext context) {
    return Checkbox(
      value: checkBoxState,
      onChanged: toggleCheckboxState!(checkBoxState),
      activeColor: Colors.lightBlueAccent,
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(2.0),
      ),
      side: MaterialStateBorderSide.resolveWith(
        (states) => BorderSide(
          width: 2.0,
          color: Colors.black,
        ),
      ),
    );
  }
}

Upvotes: 0

Views: 935

Answers (4)

user18309290
user18309290

Reputation: 8300

This means that the function is called during build,

onChanged: toggleCheckboxState!(checkBoxState),

while this calls the function when Checkbox is tapped.

onChanged: (checkBoxState) => toggleCheckboxState!(checkBoxState),

Take a look of Introduction to widgets.

Upvotes: 2

eamirho3ein
eamirho3ein

Reputation: 17880

Your toggleCheckboxState function call during building the UI, so you need to put it inside addPostFrameCallback so it run after UI builds, like this:

toggleCheckboxState: (bool checkedBoxState) {

   WidgetsBinding.instance.addPostFrameCallback((_) {
       setState(
         () {
           isChecked = checkedBoxState;
         },
       );  
   });
          
},

Upvotes: 2

Amirali Eric Janani
Amirali Eric Janani

Reputation: 1750

onChange is a Fuction(bool). try to change TaskCheckbox to this:

class TaskCheckbox extends StatelessWidget {
 final bool checkBoxState;
  final Function(bool)? toggleCheckboxState;

  const TaskCheckbox({
    super.key,
    required this.checkBoxState,
    this.toggleCheckboxState,
  });
  @override
  Widget build(BuildContext context) {
    return Checkbox(
      value: checkBoxState,
      onChanged: toggleCheckboxState!,
      activeColor: Colors.lightBlueAccent,
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(2.0),
      ),
      side: MaterialStateBorderSide.resolveWith(
            (states) => BorderSide(
          width: 2.0,
          color: Colors.black,
        ),
      ),
    );
  }
}

Upvotes: 0

Lakshydeep Vikram Sah
Lakshydeep Vikram Sah

Reputation: 39

You are changing value/state so you have to make TaskCheckbox a Stateful widget.

Upvotes: 0

Related Questions