dart 在构建期间调用了setState()或MarkNeedsBuild(),当进行违规调用时,当前正在构建微件

bqf10yzr  于 2023-02-14  发布在  其他
关注(0)|答案(4)|浏览(151)

我正试图用flutter做一个简单的测验应用程序,但这已经困扰了我一天多了
错误主要是在构建测验的过程中调用了myapp。我不知道该怎么做,即使我也在youtube上搜索过。
错误信息

主要dart代码:

import 'package:first/result.dart';
import 'package:flutter/material.dart';

import './quiz.dart';
import './result.dart';

void main(List<String> args) => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return _MyAppState();
  }
}

class _MyAppState extends State<MyApp> {
  final _questions = [
    {
      'questionText': 'What\'s your favorite colour?',
      'answers': ['Black', 'Red', 'Blue', 'Green'],
    },
    {
      'questionText': 'What\'s your favorite animal?',
      'answers': ['Cat', 'Dog', 'Pig', 'Parrot'],
    },
    {
      'questionText': 'Who\'s your favorite wrestler?',
      'answers': ['Seth Rollins', 'Roman Reigns', 'John Cena', 'Randy Orton'],
    },
  ];
  var _questionIndex = 0;

  void _answerQuestion() {
    setState(() {});
    _questionIndex = _questionIndex + 1;
    print(_questionIndex);

    if (_questionIndex < _questions.length) {
      print('We have more Questions for you !!');
    } else {
      print('No more questions left !!');
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('My First App'),
        ),
        body: _questionIndex < _questions.length
            ? Quiz(
                answerQuestion: _answerQuestion,
                questionIndex: _questionIndex,
                questions: _questions)
            : Result(),
      ),
    );
  }
}

测验. dart代码:

import './question.dart';
import './answer.dart';

class Quiz extends StatelessWidget {
  final List<Map<String, Object>> questions;
  final int questionIndex;
  final Function answerQuestion;

  Quiz({required this.questions, required this.answerQuestion, required this.questionIndex});

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Question(questions[questionIndex]['questionText'] as String),
        ...(questions[questionIndex]['answers'] as List<String>).map((answer) {
          return Answer(answerQuestion(), answer);
        }).toList()
      ],
    );
  }
}

结果。dart代码:

import 'package:flutter/material.dart';

class Result extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text('All questions are answered !!'),
    );
  }
}

答案。dart代码:

import 'package:flutter/material.dart';

class Answer extends StatelessWidget {
  final VoidCallback selectHandler;
  final String answerText;

  Answer(this.selectHandler, this.answerText);

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      width: double.infinity,
      child: RaisedButton(
          color: Colors.blue,
          textColor: Colors.white,
          onPressed: selectHandler,
          child: Text(answerText)),
    );
  }
}

问题。dart代码:

import 'package:flutter/material.dart';

class Question extends StatelessWidget {
  final String questionText;

  Question(this.questionText);

  @override
  Widget build(BuildContext context) {
    return Container(
      width: double.infinity,
      margin: EdgeInsets.all(10.0),
      child: Text(questionText,
          style: TextStyle(fontSize: 28), textAlign: TextAlign.center),
    );
  }
}

请帮帮忙。

c86crjj0

c86crjj01#

使用函数时,主要问题发生在AnswerQuiz小工具上。
Quiz上使用VoidCallback,而不是Funtion

class Quiz extends StatelessWidget {
  final List<Map<String, Object>> questions;
  final int questionIndex;
  final VoidCallback answerQuestion;

  const Quiz({
    Key? key,
    required this.questions,
    required this.answerQuestion,
    required this.questionIndex,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Question(questions[questionIndex]['questionText'] as String),
        ...(questions[questionIndex]['answers'] as List<String>).map(
          (answer) {
            return Answer(answerQuestion, answer);
          },
        ).toList()
      ],
    );
  }
}

完整片段

import 'package:flutter/material.dart';

void main(List<String> args) => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return _MyAppState();
  }
}

class _MyAppState extends State<MyApp> {
  final _questions = [
    {
      'questionText': 'What\'s your favorite colour?',
      'answers': ['Black', 'Red', 'Blue', 'Green'],
    },
    {
      'questionText': 'What\'s your favorite animal?',
      'answers': ['Cat', 'Dog', 'Pig', 'Parrot'],
    },
    {
      'questionText': 'Who\'s your favorite wrestler?',
      'answers': ['Seth Rollins', 'Roman Reigns', 'John Cena', 'Randy Orton'],
    },
  ];
  var _questionIndex = 0;

  void _answerQuestion() {
    setState(() {});
    _questionIndex = _questionIndex + 1;
    print(_questionIndex);

    if (_questionIndex < _questions.length) {
      print('We have more Questions for you !!');
    } else {
      print('No more questions left !!');
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('My First App'),
        ),
        body: _questionIndex < _questions.length
            ? Quiz(
                answerQuestion: _answerQuestion,
                questionIndex: _questionIndex,
                questions: _questions)
            : Result(),
      ),
    );
  }
}

class Quiz extends StatelessWidget {
  final List<Map<String, Object>> questions;
  final int questionIndex;
  final VoidCallback answerQuestion;

  const Quiz({
    Key? key,
    required this.questions,
    required this.answerQuestion,
    required this.questionIndex,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Question(questions[questionIndex]['questionText'] as String),
        ...(questions[questionIndex]['answers'] as List<String>).map(
          (answer) {
            return Answer(answerQuestion, answer);
          },
        ).toList()
      ],
    );
  }
}

class Answer extends StatelessWidget {
  final VoidCallback selectHandler;
  final String answerText;

  Answer(this.selectHandler, this.answerText);

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      width: double.infinity,
      child: RaisedButton(
        color: Colors.blue,
        textColor: Colors.white,
        onPressed: selectHandler,
        child: Text(answerText),
      ),
    );
  }
}

class Question extends StatelessWidget {
  final String questionText;

  Question(this.questionText);

  @override
  Widget build(BuildContext context) {
    return Container(
      width: double.infinity,
      margin: EdgeInsets.all(10.0),
      child: Text(questionText,
          style: TextStyle(fontSize: 28), textAlign: TextAlign.center),
    );
  }
}

class Result extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text('All questions are answered !!'),
    );
  }
}
ggazkfy8

ggazkfy82#

您收到错误消息的原因是每次调用MyApp小部件的build方法时都调用setState。setState方法将重新触发小部件的构建,然后再次调用setState。因此,基本上您有一个无限的重新呈现。
如果您查看quiz.dart中的代码,我们会发现这种无限重新渲染的原因:

@override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Question(questions[questionIndex]['questionText'] as String),
        ...(questions[questionIndex]['answers'] as List<String>).map((answer) {
          return Answer(answerQuestion() /*<-- here is the problem*/, answer);
        }).toList()
      ],
    );
  }

每次测验小部件调用它的build方法时,它都会调用answerQuestion方法,该方法会调用主小部件的build方法,而主小部件的build方法又会重新构建测验小部件。与其在这里调用该方法,不如将此回调方法发送到下面三个小部件中的回答小部件:
x一个一个一个一个x一个一个二个x
我还建议您更新answerQuestion方法小部件中的逻辑,这样您就可以将setState方法 Package 在您正在进行的状态更新周围:

void _answerQuestion() {
    setState(() {
       _questionIndex = _questionIndex + 1;
    });
    print(_questionIndex);

    if (_questionIndex < _questions.length) {
      print('We have more Questions for you !!');
    } else {
      print('No more questions left !!');
    }
  }
zyfwsgd6

zyfwsgd63#

根据您提供的代码,您似乎只是在main.dart代码中传递函数的示例,然后进一步传递到其他文件中。根据我使用dart和flutter的经验,强烈建议在向小部件传递函数时,始终以以下方式传递:

Quiz(
                answerQuestion: () => _answerQuestion(), // pass it like this to avoid errors.
                questionIndex: _questionIndex,
                questions: _questions)

也就是说,你应该把它作为lambda/Anonymous函数传递。

void yourFunction() {
  // You do something here
}

AnyWidget(
  onPressed: () => yourFunction();, // This is called a lambda/anonymous function.
);

这样做的原因是,当像onPressed: yourFunction,这样传递函数时,即使用户实际上没有与应用交互,也会被调用,即在构建小部件时调用。为了避免这种情况,我们使用lambda函数。
如果我的回答有帮助,请将我的回答标记为正确。谢谢!

qjp7pelc

qjp7pelc4#

测验中显示错误..(问题[questionIndex][“答案”]为..

相关问题