【问题标题】:How to instantiate final variables in Stateless Widget?如何在无状态小部件中实例化最终变量?
【发布时间】:2023-03-28 13:50:02
【问题描述】:

我正在尝试根据输入值将某些值分配给某些属性。该值在小部件的整个生命周期中保持不变。因此我使用了Stateless 小部件。但是,我无法为构造函数中的道具赋值。

class InOrOut extends StatelessWidget {
  final Condition condition;
  final bool isIconVisible;
  final Color backgroudColor;
  final Color foregrounndColor;

  InOrOut({Key key, this.condition, this.isIconVisible}) : super(key: key) {
    switch (condition) {
      case Condition.IN:
        backgroudColor = Colors.green[100];
        foregrounndColor = Colors.green[100];
        isIconVisible = false
        break;
      case Condition.ABSENT:
        backgroudColor = Colors.grey[300];
        foregrounndColor = Colors.green[100];
        isIconVisible = true;
        break;
      case Condition.OUT:
        backgroudColor = Colors.red[100];
        foregrounndColor = Colors.green[100];
        isIconVisible = false;
        break;
      default:
        backgroudColor = Colors.red[100];
        foregrounndColor = Colors.green[100];
        isIconVisible = false;
    }
  }

尝试为 prop 赋值时出现以下错误:

'foregrounndColor' 不能用作设置器,因为它是最终的。 尝试寻找不同的二传手,或使 'foregrounndColor' non-final.dart(assignment_to_final)

如果我删除 final,我将无法在 Stateless 小部件中使用它。

最后,我是否应该因此而更改为Stateful 小部件?

【问题讨论】:

  • 要保持无状态,您只需将属性声明为late final。下面的答案中的一个例子。 dart@2.14.2
  • 对于那些正在寻找这个答案的人来说,这种方法是错误的。在上面的例子中,变量可以在 build 方法中声明,而不是作为 final 调用。
  • 如果将它们放在 build 方法中,这些变量将在小部件重建时不必要地重新计算。如果这是一个简短的计算(如您的示例中),那很好。但是您示例中的这些变量直接取决于小部件的输入 (Condition),这是最终的,因此我仍然认为将它们声明为 late 并在构造函数中初始化它们的方法是可以接受的。为什么你认为这是错误的?
  • 感谢您的意见@maganap。我没有说使用迟到是错误的。我的意思是,使用像这样的无状态小部件是毫无意义的,而它们正是为此而使用的有状态小部件。我的印象是有状态的小部件对性能不利,应该避免!在这里,我可以使用带有 initState 逻辑的 Stateful 小部件。
  • 我必须说,在您的示例中,这不是有状态小部件存在的原因。我并不是说使用有状态的小部件是错误的,但如果你的变量是final,它肯定效率较低,而且绝对没有必要。如果不费吹灰之力就可以避免不必要的有状态小部件、不必要的重建以及许多其他不必要的“小”事情,从长远来看,这将有助于避免性能问题。所以,如果你可以让它保持无状态,为什么不呢?我猜是尝试遵循最佳实践的问题。

标签: flutter


【解决方案1】:

要保持小部件无状态,您需要将属性声明为late final 并在构造函数中对其进行初始化。示例:

class IntroPage extends StatelessWidget {
  IntroPage(
    this.step, {
    Key? key,
  }) : super(key: key) {
    iconData = _getIconData(step);
    title = 'This is title ${step.toString()}';
    body = _getBody(step);
  }

  final IntroStep step;
  late final IconData iconData;
  late final String title;
  late final String body;

  IconData _getIconData(IntroStep step) {
    IconData iconData;
    switch (step) {
      case IntroStep.step1:
        iconData = Icons.share_sharp;
        break;
      case IntroStep.step2:
        iconData = Icons.sailing;
        break;
      case IntroStep.step3:
        iconData = Icons.grid_view_outlined;
        break;
    }
    return iconData;
  }

  @override
  Widget build(BuildContext context) {
  ...

【讨论】:

    【解决方案2】:
    class InOrOut extends StatelessWidget {
      final Condition condition;
      final bool isIconVisible;
      final Color backgroundColor;
      final Color foregroundColor;
    
      InOrOut({Key key, this.condition, bool isIconVisible})
          : backgroundColor = condition == Condition.IN
                ? Colors.green[100]
                : condition == Condition.ABSENT ? Colors.grey[300] : condition == Condition.OUT ? Colors.red[100] : Colors.red[100],
            foregroundColor = condition == Condition.IN
                ? Colors.green[100]
                : condition == Condition.ABSENT ? Colors.green[100] : condition == Condition.OUT ? Colors.green[100] : Colors.green[100],
            isIconVisible = condition == Condition.ABSENT,
            super(key: key);
    }
    

    所以我一般看不到这种情况,我宁愿有 3-4 个单独的小部件或在 build() 方法中使用三元运算,但显然不是有状态的小部件

    【讨论】:

    • 谢谢!不过,我希望有更好的方法来做到这一点。我认为这可能会变得更加复杂,因为我需要的其余参数需要大量的三元条件。
    • @Anoop.P.A 你读过dart.dev/guides/language/language-tour#final-and-const吗?下次听从好的建议好吗?
    猜你喜欢
    • 2015-02-24
    • 2020-01-19
    • 2020-05-20
    • 2021-09-21
    • 2020-05-24
    • 2014-06-20
    • 1970-01-01
    • 2022-01-19
    • 1970-01-01
    相关资源
    最近更新 更多