Put some logic before you render a widget in flutter, best practices

Rahul Dev
4 min readDec 28, 2022

--

Problem Statement: Some times we need to place some logic before we render a widget, which may be based on the result of the calculation we wanna show in the widget or may be a conditional widget

There are several solutions or several ways you can achieve this requirement.

  1. The Builder() widget
  2. The ((){}()) widget [Recommended Solution for the given title of the story]
  3. Ternary Operator
  4. Conditional Widget inside Column/Row

Let’s discuss all the solutions and their use cases, i.e, where and when you should use each of them.

1. The Builder() widget

The code snippet for this widget is given below,

Center(
child: Builder(
builder: (BuildContext context) {
///WRITE YOUR LOGIC HERE...
return const Text('foo');
}
),
)

in this widget, the builder gives a new BuildContext and it expects a widget as a return.

Let's say you are inside a Scaffold and there only you are using a Scaffold.of(context), there it can’t get Scaffold through the context, or if it gets in the widget tree, it will wrongly identify the Scaffold

Let’s understand with code,

Code where picking the wrong scaffold,

void main() {
runApp(const MyApp());
}

class MyApp extends StatelessWidget {
const MyApp({super.key});

@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.light().copyWith(),
debugShowCheckedModeBanner: false,
home: Scaffold(
///name this as scaffold 1
appBar: AppBar(
title: const Text('InkWell works!'),
),
body: const NewScaffold()),
);
}
}

class NewScaffold extends StatelessWidget {
const NewScaffold({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
return Scaffold(
///name this as scaffold 2
body: const Center(child: Text('Hello World')),
bottomNavigationBar: ElevatedButton(
onPressed: () {
///this will pick the scaffold 1 but we want to pick scaffold 2
Scaffold.of(context).showBottomSheet((context) => Container());
},
child: const Text('My Button'),
),
);
}
}

This problem is solved by the Builder widget

Solved code where picking the the scaffold we want,

void main() {
runApp(const MyApp());
}

class MyApp extends StatelessWidget {
const MyApp({super.key});

@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.light().copyWith(),
debugShowCheckedModeBanner: false,
home: Scaffold(
///name this as scaffold 1
appBar: AppBar(
title: const Text('InkWell works!'),
),
body: const NewScaffold()),
);
}
}

class NewScaffold extends StatelessWidget {
const NewScaffold({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
return Scaffold(
///name this as scaffold 2
body: const Center(child: Text('Hello World')),
bottomNavigationBar: Builder(
builder: (context) {
///WRITE YOUR LOGIC HERE...
return ElevatedButton(
onPressed: () {
///this will pick the scaffold 2, perfect
Scaffold.of(context).showBottomSheet((context) => Container());
},
child: const Text('My Button'),
);
}
),
);
}
}

But you should not use this widget in other use cases like if you want to place some logic before we render a widget, which may be based on the result of the calculation we want to show in the widget.

But why? because it creates a new build context, now if you wrap that Builder widget with some state management widget, those will not work properly. because it is creating a new context inside the builder all the widgets present are rendering through the new context.

Still not clear, attaching a video from the official flutter channel,

2. The ((){}()) widget

This is Recommended Solution for the given Title of the story

The code snippet for this widget is given below,

Center(
child: ((){
///WRITE YOUR LOGIC HERE...
return const Text('foo');
}()),
)

Here, this will NOT create a new BuildContext, so it will work with any of the state management widgets with no problems.

((){
///WRITE YOUR LOGIC HERE...
return Widget(); ///YOU NEED TO RETURN A WIDGET
}()),

this expects a return Widget in return.

The full Code for this is given below,

void main() {
runApp(const MyApp());
}

class MyApp extends StatelessWidget {
const MyApp({super.key});

@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.light().copyWith(),
debugShowCheckedModeBanner: false,
home: Scaffold(
///name this as scaffold 1
appBar: AppBar(
title: const Text('InkWell works!'),
),
body: const NewScaffold()),
);
}
}

class NewScaffold extends StatelessWidget {
const NewScaffold({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
return Scaffold(
///name this as scaffold 2
body: const Center(child: Text('foo')),
bottomNavigationBar: (() {
///WRITE YOUR LOGIC HERE...
return ElevatedButton(
onPressed: () {
///this will pick the scaffold 1, as expected
Scaffold.of(context).showBottomSheet((context) => Container());
},
child: const Text('My Button'),
);
}()),
);
}
}

3. The Ternary widget

This is Simple, following is the Code snippet

Center(
child: (5 > 2) ? const Text("5 is greater") : const Text("2 is greater"),
)

This is useful when based on some condition you want to render either this widget or the other widget. No place to put any logic here.

4. Conditional Widget inside Column/Row

This is Simple, following is the Code snippet

Center(
child: Column(
children: [
if(5 > 2) const Text("5 is greater"),
Text("above text will appear only if condition passes")
],
)
)

This is useful when based on some condition you want to render some widget and if the condition fails you don't want to render anything. No place to put any logic here also.

--

--

Rahul Dev

Software Engineering Specialist at BT Group ◇ Ex-SSE at LendingKart, Mantra Labs