A widget’s build function should be free of side effects. Whenever the function
is asked to build, the widget should return a new tree of widgets1, regardless of what the widget previously returned. The
framework does the heavy lifting work to determine which build methods need to
be called based on the render object tree (described in more detail later). More
information about this process can be found in the Inside Flutter
topic.

On each rendered frame, Flutter can recreate just the parts of the UI where the
state has changed by calling that widget’s build() method. Therefore it is
important that build methods should return quickly, and heavy computational work
should be done in some asynchronous manner and then stored as part of the state
to be used by a build method.

While relatively naïve in approach, this automated comparison is quite
effective, enabling high-performance, interactive apps. And, the design of the
build function simplifies your code by focusing on declaring what a widget is
made of, rather than the complexities of updating the user interface from one
state to another.