# Flutter Performance Tip: Mind your build

We're developers. We like fast cars and fast Flutter.

Welcome to the first of many Flutter performance tips.

This article also has a companion video that gives the exact same information, but with music and visuals.

%[https://www.youtube.com/watch?v=vHSeUIYkTAE]

First, an overview of widgets!

![Immutable-UI-Blueprints.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1631468699263/CuyA4PWWT.gif)

**Widgets** are immutable UI blueprints for **RenderObjects**. They're meant to be recreated a lot. For Flutter to remain fast your widgets need to be created fast.

Lets explore an example. Keep in mind it's just an example to illustrate a point.

```dart
...

/// Not really long, just a demo.
const superLongListOfNames = ['Gordon', 'George', 'Hannah', 'Harry', 'Dan'];

/// Expensive operation, just a demo.
List<String> namesThatStartWith(String l) {
  print('expensive function $l');
  return superLongListOfNames
      .where((element) => element.startsWith(l))
      .toList();
}

class OhNoWidget extends StatelessWidget {
  const OhNoWidget({
    Key? key,
    required this.letter,
  }) : super(key: key);

  final String letter;

  @override
  Widget build(BuildContext context) {
    print('building');
    List<String> filteredNames = namesThatStartWith(letter); // This is the ouchie

    return ListView.builder(
      itemCount: filteredNames.length,
      itemBuilder: (context, index) {
        return Padding(
          padding: const EdgeInsets.all(32.0),
          child: _Tile(title: filteredNames[index]),
        );
      },
    );
  }
}

...
```

Above you have a **StatelessWidget**; this widget takes in a **String** property, called `letter`.

You use this property to filter a long list of names that start with that letter. You have a function called `namesThatStartWith` and you filter the list `superLongListOfNames`.

You call this function in the `build` method, and then you use the result to display the names that start with that letter.

There are two problems with this widget.

First, if you assume this list is really long, then you should probably do this operation in a separate isolate instead. We'll talk about isolates in a future article.

Seconds, you're calling `namesThatStartWith` from the widget's `build` method; this is the main issue that we're focussing on in this article.

This means this operation will be performed EVERY time the build method is called. Meaning any time a parent is updated, or new (unrelated) state is passed in, or the user navigates the app. The build method is SUPPOSED to be called a lot, and that is part of how Flutter is designed. Also, keep in mind that you don't always have control over when a build is triggered.

Here is an example of what this output would look like:

![demo_screen.jpg](https://cdn.hashnode.com/res/hashnode/image/upload/v1631472027575/2Qerdk6gX.jpeg)

There's an extra button to trigger a call to `setState` higher up in the widget tree.

When that button is tapped the `build` method will be called again and as a side effect the expensive function will be called as well.

Keep your build method pure and free of side effects!

In this example you can fix the issue by making this a **StatefulWidget**, and moving the call to the expensive function to `initState`.

```dart
class OhNoWidget extends StatefulWidget {
  const OhNoWidget({
    Key? key,
    required this.letter,
  }) : super(key: key);

  final String letter;

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

class _OhNoWidgetState extends State<OhNoWidget> {
  late List<String> filteredNames;

  @override
  void initState() {
    super.initState();
    filteredNames = namesThatStartWith(widget.letter); // Moved here
  }

  @override
  Widget build(BuildContext context) {
    print('building');

    return ListView.builder(
      itemCount: filteredNames.length,
      itemBuilder: (context, index) {
        return Padding(
          padding: const EdgeInsets.all(32.0),
          child: _Tile(title: filteredNames[index]),
        );
      },
    );
  }
}
```

And there you go 👍🏼. Point is to keep your builds clean and don't do expensive work directly in the build. Extract that logic to whatever form of state management you use.

This logic would look different depending on how you manage your state and trigger rebuilds in your app.

For this particular example when using `setState`, take note that if the `letter` property you pass in were to change, then you'd need to filter the list again.

You can do that by overriding `didUpdateWidget`.

Just add a check to see if the `oldWidget.letter` value and the new `widget.letter` value are different. If yes, recompute and set the local `filteredNames` state.

```dart
@override
  void didUpdateWidget(OhNoWidget oldWidget) {
    super.didUpdateWidget(oldWidget);

    if (oldWidget.letter != widget.letter) {
      filteredNames = namesThatStartWith(widget.letter);
    }
  }
```

That's that!

Ask question down below, and let me know ideas for future performance tips. Until then, code fast, Flutter faster. Cheers.
