Sample code for this article

An overview of the

Reactive programming frameworks have a constant theme of “state management”. Whether React/Vue or Flutter, their problems and solutions are the same

Er… .What responsive programming means????????

Responsive programming, the following answers refer to baidu Encyclopedia:

Responsive programming is a paradigm for data flow and change propagation

In imperative programming, a+b = C means that the result of an expression is assigned to C, and that subsequent changes to B or C do not affect A

In reactive programming, the value of C is updated as the value of A or B is updated

Now I see that response is what programming is all about

In the example above, a and B refer to the state, while C refers to what the user can see, such as the interface.

That is, when the state changes, the page refreshes,

Responsive programming solves the problem of data consistency. Ensure that state changes can be immediately synchronized to the page;

FlutterState management in

Who should manage the state of a StatefulWidget in Flutter?

The Widget itself? Parent Widget or another object to manage? The answer is that it depends

The following are the most common ways to manage state:

  • Widgets manage their own state

    If the state is related to the appearance of the interface, such as color or animation, then the state is best managed by the Widget itself

  • Widgets manage the state of child widgets

    If the state is user data, such as the selected state, the position of the slider, then the state is best managed by the parent Widget

  • Mixed management (both parent and child widgets manage state)

    If a state is shared by different widgets, it is ultimately managed by their common parent Widget

It is better to manage state encapsulation inside the Widget, but more flexible to manage state inside the parent Widget. Sometimes, if you are not sure exactly how to manage it, the first choice is to manage it in the parent Widget.

practice

  • Widgets manage their own state

    class _TapBoxAState extends State<TapBoxA> {
      bool _active = false;
    
      void_handleTap() { setState(() { _active = ! _active; }); }@override
      Widget build(BuildContext context) {
        return GestureDetector(
          onTap: _handleTap,
          child: Container(
            width: 200,
            height: 200,
            child: Center(
              child: Text(_active ? "Active" : "Inactive",
                  style: TextStyle(fontSize: 32, color: Colors.white)), ), decoration: BoxDecoration(color: _active ? Colors.lightBlue : Colors.green), ), ); }}Copy the code

  • The parent Widget manages the state of the child widgets

    It is often a good idea for the parent Widget to manage state and tell the child widgets that updates are appropriate. For example, an IconButton is an IconButton. It is a stateless Widget, because our parent Widget needs to know if the button is clicked to act accordingly

    Example:

    //------------------------ ParentWidget -----------------------
    class ParentWidget extends StatefulWidget {
      @override
      State<StatefulWidget> createState() => _ParentWidgetState();
    }
    
    class _ParentWidgetState extends State<ParentWidget> {
      bool _active = false;
    
      void _handleTapBoxChanged(bool newValue) {
        setState(() {
          _active = newValue;
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return newContainer( child: TapBoxB( active: _active, onChange: _handleTapBoxChanged, ), ); }}//------------------------ TapBoxB -----------------------
    class TapBoxB extends StatelessWidget {
      final bool active;
      final ValueChanged<bool> onChange;
    
      TapBoxB({Key key, this.active, this.onChange});
    
      @override
      Widget build(BuildContext context) {
        return GestureDetector(
          child: Container(
            width: 200,
            height: 200,
            child: Center(
              child: Text(active ? "Active" : "Inactive",
                  style: TextStyle(fontSize: 32, color: Colors.white)),
            ),
            decoration:
                BoxDecoration(color: active ? Colors.lightBlue : Colors.green),
          ),
          onTap: () => onChange(!active),
        );
      }
    }
    Copy the code

    In the previous example, TapBoxB passes its state to the parent through callbacks. The state is managed by the parent, so its parent is StatefullWidget, but since TapBoxB does not manage any state itself, it is a StatelessWidget

    The build method is re-executed each time the setState is set, passing the state to the child components, so TabBoxB doesn’t need to manage the state

    The result is the same as shown above

  • Mixed state management

    For some components, a hybrid management approach can be useful, with the component managing some internal state and the parent managing some other external state

    Example:

    //------------------------ ParentWidget -----------------------
    class ParentWidget extends StatefulWidget {
      @override
      State<StatefulWidget> createState() => _ParentWidgetState();
    }
    
    class _ParentWidgetState extends State<ParentWidget> {
      bool _active = false;
    
      void _handleTapBoxChanged(bool newValue) {
        setState(() {
          _active = newValue;
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return newContainer( child: TapBoxC( active: _active, onChange: _handleTapBoxChanged, ), ); }}//------------------------ TapBoxC -----------------------
    class TapBoxC extends StatefulWidget {
      final bool active;
      final ValueChanged<bool> onChange;
    
      TapBoxC({Key key, this.active, this.onChange});
    
      @override
      State<StatefulWidget> createState() => _TapBoxCState();
    }
    
    class _TapBoxCState extends State<TapBoxC> {
      bool _highlight = false;
    
      void _handleTapDown(TapDownDetails detailis) {
        setState(() {
          _highlight = true;
        });
      }
    
      void _handleTapUp(TapUpDetails detailis) {
        setState(() {
          _highlight = false;
        });
      }
    
      void _handleTapCancel() {
        setState(() {
          _highlight = false;
        });
      }
    
      void_handleTap() { widget.onChange(! widget.active); }@override
      Widget build(BuildContext context) {
        return GestureDetector(
          onTap: _handleTap,
          onTapDown: _handleTapDown,
          // Press event
          onTapUp: _handleTapUp,
          // Lift the event
          onTapCancel: _handleTapCancel,
          // Cancel the event
          child: Container(
            width: 200,
            height: 200,
            child: Center(
              child: Text(widget.active ? "Active" : "Inactive",
                  style: TextStyle(fontSize: 32, color: Colors.white)),
            ),
            decoration: BoxDecoration(
                color: widget.active ? Colors.lightBlue : Colors.green,
                border: _highlight
                    ? Border.all(color: Colors.teal[700], width: 10)
                    : null),),); }}Copy the code

    The effect is as follows:

    A border appears when the finger is pressed, the border disappears when the finger is lifted, and the color of the component changes when the tap is complete

    For developers, the only thing they care about is whether the component is in the Active state, not the implementation of the border, so we hide the border state internally and expose only the Active state externally

  • Global state management

    When the application needs some cross-component, routing state needs to be synchronized, the above methods are not adequate. For example, when we change the language of the App on the Settings page, we expect the language-dependent components in the App to be rebuilt when the language state changes in order for the Settings to take effect in real time. However, these language-dependent components are not together, so this situation is difficult to manage using the above methods

    It is correct to handle this communication between distant components through a global state manager. There are two solutions:

    1. Implement a global event bus, which corresponds to the change of language state as an event, and subscribe to the language change event in the initState method of language-dependent components in App. When the user switches language, the component subscribing to this event will receive notification, and reset state after receiving the notification

    2. Use some special packages for state management, such as Provider, Redux, etc. For specific use, you can check the details in pub

reference

Flutter of actual combat