【问题标题】:StreamBuilder / ChangeNotifierProvider- setState() or markNeedsBuild() called during buildStreamBuilder / ChangeNotifierProvider- setState() 或 markNeedsBuild() 在构建期间调用
【发布时间】:2022-06-19 01:31:47
【问题描述】:

Streambuilder、ChangeNotifier 和 Consumer 无法弄清楚如何正确使用。颤动

我已经尝试了,尝试了,我已经搜索了很多,但我无法弄清楚: 我正在使用 Streambuilder 这应该更新应该在我的 Consumer 小部件中触发重建的 ChangeNotifier。据说... 但即使我使用 (listen: false) 选项调用提供程序,我也会遇到此错误

在为 HealthCheckDataNotifier:setState() 或 markNeedsBuild() 在期间调用 建造。发出违规调用时当前正在构建的小部件是: StreamBuilder

重要提示:我无法尽快创建流,因为我需要在阅读 firebase 之前收集其他信息,请参阅 (userMember: userMember)

Widget build(BuildContext context) {
  return MultiProvider(
      providers: [
        /// I have other provider...
        ChangeNotifierProvider<HealthCheckDataNotifier>(create: (context) => HealthCheckDataNotifier())
       
      ],
 child: MaterialApp(...

那么我的更改通知器看起来像这样

class HealthCheckDataNotifier extends ChangeNotifier {
  HealthCheckData healthCheckData = HealthCheckData(
      nonCrewMember: false,
      dateTime: DateTime.now(),
      cleared: false,
      );

  void upDate(HealthCheckData _healthCheckData) {
    healthCheckData = _healthCheckData;
    notifyListeners();
  }
}

然后是 Streambuilder

return StreamBuilder<List<HealthCheckData>>(
        stream: HeathCheckService(userMember: userMember).healthCheckData,
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.active) {
            if (snapshot.hasData) {
              if (snapshot.data!.isNotEmpty) {
                healthCheckData = snapshot.data?.first;
              }

              if (healthCheckData != null) {
                timeDifference = healthCheckData!.dateTime.difference(DateTime.now()).inHours;
                _cleared = healthCheckData!.cleared;
                if (timeDifference < -12) {
                  healthCheckData!.cleared = false;
                  _cleared = false;
                }
///The problem is here but don't know where to put this or how should be done

                Provider.of<HealthCheckDataNotifier>(context, listen: false).upDate(healthCheckData!);
              } 
            }
            return Builder(builder: (context) {
              return Provider<HealthCheckData?>.value(
                value: healthCheckData,
                builder: (BuildContext context, _) {
                  return const HealthButton();
                },
              );
            });
          } else {
            return const Text('checking health'); //Scaffold(body: Loading(message: 'checking...'));
          }
        });

最后是消费者(注意:消费者在另一条路线上)

return Consumer<HealthCheckDataNotifier>(
      builder: (context, hN, _) {
        if (hN.healthCheckData.cleared) {
          _cleared = true;
          return Container(
            color: _cleared ? Colors.green : Colors.amber[900],

希望足够清晰, 非常感谢您的宝贵时间!

【问题讨论】:

    标签: flutter consumer stream-builder flutter-change-notifier flutter-streambuilder


    【解决方案1】:

    无法在构建器回调中设置状态

    就像你没有在 React 渲染中设置状态

    const A =()=>{
       const [state, setState] = useState([])
       return (
       <div>
         {setState([])}
         <p>will not work</p>
       </div> 
       )
    }
    

    由于明显的原因它不起作用,render --> setState --> render --> setState --> (无限循环)

    所以解决方案类似于我们在 React 中的做法,将它们移动到 useEffect

    class _MyAppState extends Stateful<MyApp> {
      StreamSubscription<User?>? _userStream;
      var _loadingUserWaiting = true;
      var _loadingUserError = false;
      var _loadingUserSuccess = false;
      User? _user;
    
      @override
      void initState() {
        super.initState();
        _userStream = FirebaseAuth.instance.authStateChanges().listen((user) async {
          setState(() {
            _loadingUserError = false;
            _loadingUserWaiting = false;
            _loadingUserSuccess = true;
          });
          _user = user;
        }, onError: (error) {
          setState(() {
            _loadingUserWaiting = false;
            _loadingUserSuccess = false;
            _loadingUserError = true;
          });
        });
      }
      @override
      void dispose() {
        super.dispose();
        _userStream?.cancel();
      }
    
      @override
      Widget build(context) {
        return Container()
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2018-05-15
      • 2020-10-05
      • 2020-12-12
      • 2020-12-28
      • 2021-01-06
      • 2021-06-06
      • 2021-05-31
      • 2021-08-24
      相关资源
      最近更新 更多