0

这个问题之后,我理解了为什么StatefulWidgets在基于 Redux 的颤振应用程序的上下文中确实有意义。这也是我想要完成的——

一个页面,它是来自应用程序范围状态的“馈送”信息(登录用户详细信息、api 数据等),并且还可以从其连接的 ViewModel 调度操作,但它还包含范围较小、寿命短的有状态小部件状态。诸如动​​画之类的东西,在提交之前动态验证用户输入,以及根据用户操作更改 UI。

所以我对这里的方法很感兴趣,希望有人可以帮助我。目前我所有的“页面”都是通过商店连接到应用程序状态的无状态小部件,方式如下:

class LoginPage extends StatelessWidget {
  final String TAG = "LoginPage";
  bool isGreen = false;

  LoginPage({Key key}) : super(key: key);

  void changeColor() {
    isGreen = !!isGreen;
  }


  @override
  Widget build(BuildContext context) {
    /// [StoreConnector] is used to convert store data (using the fromStore)
    /// into a ViewModel suitable for the page.
    return StoreConnector<AppState, LoginPageViewModel>(
        builder: (context, viewModel) {
          return Scaffold(
              body: Column(
               children: <Widget>[
                Container(...),
                Text(
                  text: viewModel.some_value_from_the_store,
                  color: isGreen ? Colors.green : Colors.red,
                ),
                ElevatedButton(
                  onPressed: () => changeColor(),
                  child: Text('Press to change color'),
                )
            ],
          ));
        },
        converter: LoginPageViewModel.fromStore);
  }
}

在这里,我只是尝试根据用户点击简单地更改“LoginPage”小部件内的文本颜色,同时仍保持与商店的连接,以便 UI 在新的应用程序状态信息到达时不断更新。

我们那里有这样的参考吗?谁能提供一个例子,或者只是如何实现这一目标的基本准则?看起来很简单,但我正在努力解决它。

4

1 回答 1

1

这里有一些可能会有所帮助的想法。

您的小部件需要有状态。您正在尝试跟踪将随时间变化的颜色。无状态小部件只允许最终属性 - 即您只能在创建时启动它们的值。

您的变量 isGreen 和方法 changeColor() 应该是状态对象的一部分。你的 build() 方法也会去那里。

接下来 - 当你调用你的方法时,你应该调用:

void changeColor() {
    setState(() {isGreen = !isGreen;});
}

我认为在您的代码中您没有翻转值(=!!iGreen 与 =isGreen 相同)。但更重要的是 - 你没有告诉框架你的小部件应该被重建。您可以自己测试一下:单击一次(在您更正“!!”之后)。什么都不会发生。如果您在模拟器中强制刷新 - 您应该会看到颜色确实发生了变化。这是因为您手动刷新了它。setState() 为您完成:它将运行您提供的代码,然后调用 Flutter 告诉它刷新您的小部件。看——flutter 没有魔法触发器,也不会观察你的代码来决定何时刷新你的小部件。setState() 告诉它这样做。

作为一般规则:您的应用程序状态 - 即与多个小部件(或页面)共享的数据应该“提升”小部件树,并保存在 Provider 类中。

有状态的小部件应该只保留与它们直接相关的数据,并且只与它们相关。通常,这是有助于呈现提供者数据的数据。例如: -Provider 将保留您显示的项目列表。您的 statefull 小部件将跟踪当前选定的项目 -Provider 保留要显示的文本。您的有状态小部件保留字体大小、字体颜色等,允许用户在该特定小部件上更改它,但不能在所有使用相同数据的小部件上进行更改。

在您的示例中 - 您的云在屏幕上有多个登录小部件(出于某种原因)。在这种情况下: - 如果您希望所有登录小部件更改颜色 - 将 isGreen 保留在您的提供程序类中。在这种情况下,您的小部件可以是无状态的。- 如果您只想要您单击的小部件来更改颜色 - 这属于您的有状态小部件,因为没有其他人关心这个值。

让我用应该做你想做的代码来更新它。将小部件连接到商店的方式与 Stateful 和 Steteless 小部件的工作方式相同。

注意 - 我注释掉了您连接到商店的代码,只是为了显示您的小部件将如何更改颜色。取消注释商店代码,你应该很高兴。

您可以在https://dartpad.dev/中快速运行,只需复制/粘贴代码。

// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: LoginPage(),
    );
  }
}

class LoginPage extends StatefulWidget {
  final String TAG = "LoginPage";
  LoginPage({Key key}) : super(key: key);
  
  @override
  _LoginPageState createState() => _LoginPageState();
}

class _LoginPageState extends State<LoginPage> {
  
  bool isGreen = false;

  void changeColor() {
    setState(() {
      isGreen = !isGreen;
    });
    
  }

  @override
  Widget build(BuildContext context) {
    /// [StoreConnector] is used to convert store data (using the fromStore)
    /// into a ViewModel suitable for the page.
    //return StoreConnector<AppState, LoginPageViewModel>(
        //builder: (context, viewModel) {
          return Scaffold(
              body: Column(
               children: <Widget>[
                Container(),
                Text(
                  'viewModel.some_value_from_the_store',
                  style: TextStyle(color: isGreen ? Colors.green : Colors.red),
                ),
                ElevatedButton(
                  onPressed: () => changeColor(),
                  child: Text('Press to change color'),
                )
            ],
          ));
        //},
        //converter: LoginPageViewModel.fromStore);
  //}
}
}
于 2021-01-24T09:16:45.470 回答