Sudoku Solver in Flutter — Understanding Flutter State Management by Example — Part 3

Nikhil Heda
4 min readApr 7, 2020

Hey guys!

Welcome to Part 3, where we discuss a solution using inherited widgets — do read Part 1 and Part 2 to understand how we got here.

Design 2 : Using Inherited Widget — I am close…

The design using just stateful widgets clearly has a lot of problems, lets start solving them.

The main problem in previous design is that we are maintaining the shared state everywhere in the widget tree. A better approach would be to maintain it at one place and then make this accessible to the widget tree.

Step 1: Define shared data and operations at one place, and expose it to those who need it. This is what a service class does. So we need a Shared State service class.

Step 2: Make the service class accessible to the widgets in the widget tree. We use InheritedWidget for this.

Inherited widgets — A 5 second description

  1. It makes data accessible to all widgets in the tree.
  2. Data should be final (as InheritedWidgets should be immutable), so we can’t maintain board and activeNumber within this as they keep changing, hence we abstract it out to a service, and then make the service final.

Refer this for more details —

Who is responsible for shared state?

Since we are moving all our shared data/operations to a service class — the service class is now responsible for handling them. This service is in turn, maintained by the inherited widget.

Widget Tree

First, lets see how our widget tree changes —

Code

Github: https://github.com/NikhilHeda/SudokuSolver/tree/design2

SudokuSolverService

We first create a service class — SudokuSolverService.

This class defines board and activeNumber and exposes them through getters and setters. We also have operations like solveBoard() and resetBoard() defined in the same class.

SudokuSolverService

SharedStateWidget

We implement a custom InheritedWidget called SharedStateWidget. This has the service class attribute defined as final.

We wrap the SudokuSolverPage widget with the SharedStateWidget, to make the service attribute accessible to all its children (this includes, SudokuCell, KeyPadCell, Solve and Reset buttons) — lifting state up!

SharedStateWidget

Solve and Reset Buttons

A click on solve or reset button changes the board and needs to rebuild the widget, hence, operations to be done in setState().

We get access to solveBoard() and resetBoard() operations from the SudokuSolverService using the SharedStateWidget —

Solve and Reset Buttons

SudokuBoard and KeyPad

SudokuBoard and KeyPad reset to original implementation — Clean code!

We remove the board and activeNumber definitions from all the widgets in the widget tree — now maintained by the service class.

SudokuBoard and KeyPad widgets

SudokuCell

This continues as a stateful widget. No constructor required as we are not maintaining shared state.

A click on sudoku cell, should change the board value at (row, col) to activeNumber and rebuild widget (hence, inside setState()).

We use the getter (getBoardCell(row, col)) and setter (setBoardCell(row, col)) for board cell value from the service supplied by the SharedStateWidget.

SudokuCell widget

KeyPadCell

Continues to be a stateless widget. No constructor required as we are not maintaining shared state.

A click on keypad cell, should change the active number to that cell’s number using the setActiveNumber() method from the service supplied by the SharedStateWidget.

KeyPadCell widget

Problems

So this is a pretty decent code. We can just stop here and accept this as a solution, because —

  1. We have all shared stuff at one place, hence we can easily maintain/extend it
  2. Code noise is reduced and each widget makes more sense semantically.

But, we still have the problem of performance — rebuilding the entire widget tree when widget state changes — we still have stateful widgets!

Lets see how to get rid of them, so that our widget tree builds/rebuilds a bit more efficiently.

InheritedWidget is kind of a low-level widget (didn’t know this), there are modules/packages out there, which use this to develop better abstractions for handling data sharing.

Up Next!

Get rid of those stateful widgets using providers— Part 4

--

--