This is the sixth day of my participation in the August More text Challenge. For details, see: August More Text Challenge

preface

In the last two articles, we introduced using InheritedWidget to go deeper into state management and decouple components from state management, making your code easier to maintain and enabling local refreshes. Last two articles portal:

  • Learn about status management from InheritedWidget (1)

  • Learn about status management from InheritedWidget (2)

Whether it is possible to implement local refresh, we will use an example to verify.

Assuming that

Going back to our previous story, the story of Fu and Reese’s blind date, assuming that our Reese is not so wooden, he can read Fu’s mind (shared state), then maybe the ending is not the way it was before. We do this with a ModelBinding and a primitive setState, respectively.

Use ModelBinding for state sharing

In order to use ModelBinding to achieve state sharing, we need to make Reith and Xiao Fu as subcomponents of ModelBinding. At the same time, we wrote a separate state-independent component (StatelessNoDepend), also placed in the child of the ModelBinding, to verify that the local refresh is valid.

class StatefulStatelessDemoPage extends StatelessWidget {
  StatefulStatelessDemoPage({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('after three years'),
      ),
      body: ModelBindingV2(
        child: Column(
          children: [
            Xiaofu3(),
            Leisi(),
            StatelessNoDepend(),
          ],
        ),
        create: () => FaceEmotion(emotion: 'surprise'),),); }}Copy the code

Meanwhile, in the Leisi component, we display the data in the state as a text, in this case a mood description string. This is shared from state management because it depends on the state, so it will be rebuilt when the state changes.

@override
Widget build(BuildContext context) {
    print('ModelBinding=====build: Reith ');
    return Center(
      child: Text(
          'ModelBinding===== Reese felt Xiao Fu's${ModelBindingV2.of<FaceEmotion>(context).emotion}')); }Copy the code

Similarly, in Xiaofu3, we also read the mood string of the state and used a button to change the mood, thus causing the component to refresh.

@override
Widget build(BuildContext context) {
    print('ModelBinding=====build: Xiao Fu ');
    return Center(
      child: Column(children: [
        Text(
            'ModelBinding=====${ModelBindingV2.of<FaceEmotion>(context).emotion}'),
        TextButton(
            onPressed: () {
              ModelBindingV2.update<FaceEmotion>(
                  context, FaceEmotion(emotion: 'happy'));
            },
            child: Text("Fuv's face changed.")))); }Copy the code

To see if it’s really being rebuilt, we print a message in the build method of the three components (Leisi, Xiaofu3, and StatelessNoDepend), and we also print the build message in the constructor. After running, we click the button and the whole printed information is as follows:

Flutter: ModelBinding=====constructor: xiaofei Flutter: ModelBinding=====constructor: Constructor: constructor Status-independent component flutter: ModelBinding=====build: Little Fluff flutter: ModelBinding===== Build: Reese Flutter: Build: don't depend on the state of the component -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - flutter: ModelBinding = = = = = build: xiao fu flutter: ModelBinding = = = = = build: lasseCopy the code

Below the separator line is the print information after clicking the button. You can see that the first time the build method is invoked for all three components. When the button is clicked, only Leisi and Xiaofu’s build methods are called, indicating that the local refresh effect is indeed implemented — components that do not depend on state are not rebuilt.

Use setState to share the state

Using setState is a bit more complicated. We need to pass data from the parent to the child component, and then update the child component by calling setState when the state changes. In this case, we need to pass the parent’s update state method to the child component that changed the state. Obviously, the coupling is very high.

class SetStateDemo extends StatefulWidget {
  SetStateDemo({Key key}) : super(key: key);

  _SetStateDemoState createState() => _SetStateDemoState();
}

class _SetStateDemoState extends State<SetStateDemo> {
  FaceEmotion faceEmotion = FaceEmotion();

  void updateEmotion(FaceEmotion newEmotion) {
    if (faceEmotion != newEmotion) {
      setState(() {
        faceEmotion = newEmotion;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('setState way'), ), body: Column( children: [ StatelessXiaofu(face: faceEmotion, updateEmotion: updateEmotion), StatelessLeisi(face: faceEmotion), StatelessNoDepend(), ], ), ); }}Copy the code

The rest of the code is so simple that I won’t post it. Now look at the whole process of going to the page and clicking the button to change the state.

Flyflutter: setState=====constructor: flyflutter: setState=====constructor: flyflutter: constructor: flyflutter: setState SetState = = = = = build: xiao fu flutter: setState = = = = = build: lasse flutter: build: don't depend on the state of the components -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- flutter: SetState =====constructor: flyflutter: setState=====constructor: flyflutter: flyflutter: flyflutter: flyflutter SetState =====build: xiaofu flutter: setState=====build: Reese flutter: build: components that are not dependent on stateCopy the code

As you can see, the process of entering the page for the first time is the same as for ModelBinding. However, when the setState method is called with the click of the button, it is completely different. Using the ModelBinding method only calls the build method that depends on the state. After setState, all the child components are reconstructed. That is, the new component is removed and then inserted — and the performance cost is certainly much higher than the ModelBinding. So what’s going on with the setState process? We will analyze it through the source code in the next article.

conclusion

This article compares using the InheritedWidget for state sharing with using the setState method. It is clear that using the InheritedWidget method has higher performance and local refreshes. And there’s no setState refactoring of the entire component tree. This feature is important because it means that we should avoid using the setState refresh interface directly on high-level components as much as possible, relying instead on state management for local refreshes. Of course, if the component itself is a leaf of the component tree, there is no performance penalty for using setState, and there is no need to use a state management tool.


I’m an island user with the same name on wechat. This is a column on introduction and practice of Flutter.

👍🏻 : feel a harvest please point to encourage!

🌟 : Collect articles, convenient to read back!

💬 : Comment exchange, mutual progress!