BLOC 状态更改后有状态小部件未重建

Fai*_*cia 3 flutter flutter-layout

我无法理解为什么我的 Stateful 小部件在重建后没有更新状态。我有一个有状态的小部件,负责每秒递减一个计数器,因此它收到一个初始值,我将此初始值传递给状态并开始递减它。

它还具有一个按钮,当按下该按钮时,会向我的块发送一个事件,该块会使用新的初始值重建有状态小部件,事实是,它确实发送并更新初始值,但计数器继续递减旧值,我没有知道为什么。这是代码示例:

小部件

void main() => runApp(
      BlocProvider(
        create: (context) => TBloc(),
        child: MaterialApp(
          home: Scaffold(
            body: BlocBuilder<TBloc, BState>(
              builder: (context, state) {
                if (state is BState) {
                  return Column(
                    children: [
                      Counter(state.value),
                      FlatButton(
                        child: Text("tap"),
                        onPressed: () =>
                            BlocProvider.of<TBloc>(context).add(BEvent(200)),
                      ),
                    ],
                  );
                }
                return Container();
              },
            ),
          ),
        ),
      ),
    );

class Counter extends StatefulWidget {
  final int initialValue;

  Counter(this.initialValue);

  @override
  CounterState createState() => CounterState(this.initialValue);
}

class CounterState extends State<Counter> {
  Timer timer;
  int value;

  CounterState(this.value);

  @override
  void initState() {
    super.initState();
    timer = Timer.periodic(Duration(seconds: 1), (timer) {
      setState(() => --value);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        Text("Value: $value"),
        Text("Initial: ${widget.initialValue}")
      ],
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

集团

class TBloc extends Bloc<BEvent, BState> {
  @override
  BState get initialState => BState(100);

  @override
  Stream<BState> mapEventToState(BEvent event) async* {
    yield BState(event.value);
  }
}

class BEvent extends Equatable {
  final int value;

  BEvent(this.value);

  @override
  List<Object> get props => [value];
}

class BState extends Equatable {
  final int value;

  BState(this.value);

  @override
  List<Object> get props => [value];
}
Run Code Online (Sandbox Code Playgroud)

先感谢您。

Mig*_*ivo 5

这是因为您只Timer在您的 上设置了您Counter的,每个小部件生命周期initState调用一次。

基本上,当您Counter第一次构建时,它将调用initState(),并且只要它保留在该小部件树中,只有didUpdateWidget()和/或didChangeDependencies()将被调用以更新 小部件(例如,当使用新参数重建时,就像您正在做的那样) )。

方法也会发生同样的情况,这与仅调用一次dispose()相反,但这次是在从树中删除小部件时调用。initState()

另外,您在这里使用状态的方式是错误的。您不需要将参数传递给状态本身(就像您所做的那样:

 CounterState createState() => CounterState(this.initialValue);
Run Code Online (Sandbox Code Playgroud)

相反,您可以通过调用以下方式访问该小部件中的所有参数:widget.initialValue

因此,综上所述,基本上,您要做的就是Counter根据新的更新来更新您的小部件,如下所示:

class Counter extends StatefulWidget {
  final int initialValue;

  Counter(this.initialValue);

  @override
  CounterState createState() => CounterState();
}

class CounterState extends State<Counter> {
  Timer timer;
  int value;

  void _setTimer() {
    value = widget.initialValue;
    timer = Timer.periodic(Duration(seconds: 1), (timer) {
      setState(() => --value);
    });
  }

  @override
  void initState() {
    super.initState();
    _setTimer();
  }

  @override
  void didUpdateWidget(Counter oldWidget) {
    super.didUpdateWidget(oldWidget);
    if(oldWidget.initialValue != widget.initialValue) {
     _setTimer();
   }
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        Text("Value: $value"),
        Text("Initial: ${widget.initialValue}")
      ],
    );
  }
}
Run Code Online (Sandbox Code Playgroud)