如何在Stateless Widget中实例化final变量?

6

我试图根据输入值对某些属性进行赋值。该值在小部件的生命周期内保持不变。因此,我使用了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'不能用作setter,因为它是final的。尝试找到另一个setter或将'foregrounndColor'设置为non-final。
如果我删除final,那么我不能在Stateless小部件内使用它。
最后,因为这个问题我应该改为使用Stateful小部件吗?

为了保持无状态,您可以将属性声明为“late final”。下面的答案中有一个示例。dart@2.14.2 - maganap
对于那些在查找这个答案的人来说,这种方法是错误的。在上面的示例中,变量可以在构建方法中声明,而不是将它们作为 final 调用。 - Anoop Thiruonam
如果将它们放在构建方法中,当小部件重建时,这些变量将被不必要地重新计算。如果是短时间的计算(就像你的例子一样),那么没问题。但是,在你的例子中,这些变量直接依赖于小部件的输入(Condition),而Condition是最终的,所以我仍然认为在构造函数中声明它们为late并进行初始化的方法是可接受的。你为什么认为这是错误的呢? - maganap
感谢您的回复,@maganap。我并没有说使用late是错误的。我的意思是像这样使用无状态小部件是毫无意义的,因为它们正好有有状态小部件可以使用。我曾经认为有状态小部件会影响性能,应该避免使用!在这里,我可以使用一个带有initState逻辑的有状态小部件。 - Anoop Thiruonam
2
在你的例子中,Stateful widget 的存在并不是那个原因,我必须说。我的意思不是使用 Stateful widget 是错误的,但它肯定不够高效,并且如果你的变量是 final,那么它绝对是不必要的。如果你可以轻松地避免不必要的 Stateful widgets、不必要的重建以及许多其他不必要的“小”事情,长期来看,这将有助于避免性能问题。所以,如果你可以保持 Stateless,为什么不呢?我想这是遵循最佳实践的问题。 - maganap
2个回答

6
为了保持小部件的无状态性,您需要将属性声明为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) {
  ...

1
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 Thiruonam
@Anoop.P.A,你有没有看过https://dart.dev/guides/language/language-tour#final-and-const?下次记得听取好的建议,好吗? - pskink

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接