Question #36EasyFlutter Basics

What is super key in flutter ?

#flutter

Answer

Overview

The super key in Flutter refers to using the

text
super
keyword with the
text
key
parameter in widget constructors. It passes the key to the parent class (superclass) constructor, enabling Flutter to identify and differentiate widgets in the widget tree.


What is a Key?

A key is a unique identifier for widgets. It helps Flutter identify which widgets changed, moved, or were removed.

dart
class MyWidget extends StatelessWidget {
  const MyWidget({Key? key}) : super(key: key);
  //                          ^^^^^^^^^^^^^^^^
  //                          This is "super key"
}

Why Use super(key: key)?

1. Pass Key to Parent Class

Widgets inherit from

text
StatelessWidget
or
text
StatefulWidget
, which expect a
text
key
parameter.

dart
// StatelessWidget constructor requires key
abstract class StatelessWidget extends Widget {
  const StatelessWidget({Key? key}) : super(key: key);
}

// Your widget passes key to parent
class MyWidget extends StatelessWidget {
  const MyWidget({Key? key}) : super(key: key);
  //                          ^^^^^^^^^^^^^^^^
  //                          Passes key to StatelessWidget
}

2. Enable Widget Identification

Keys help Flutter track widgets across rebuilds.

dart
// Without key
class TodoList extends StatelessWidget {
  final List<String> todos;
  
  const TodoList(this.todos);
  
  
  Widget build(BuildContext context) {
    return Column(
      children: todos.map((todo) => TodoItem(todo)).toList(),
    );
  }
}

// With key
class TodoList extends StatelessWidget {
  final List<String> todos;
  
  const TodoList(this.todos, {Key? key}) : super(key: key);
  
  
  Widget build(BuildContext context) {
    return Column(
      children: todos
          .map((todo) => TodoItem(
                todo,
                key: ValueKey(todo),  // Unique key for each item
              ))
          .toList(),
    );
  }
}

Types of Keys

1. ValueKey

Use when items have unique values.

dart
class TodoItem extends StatelessWidget {
  final String todo;
  
  const TodoItem(this.todo, {Key? key}) : super(key: key);
}

// Usage
TodoItem('Buy milk', key: ValueKey('Buy milk'))

2. ObjectKey

Use when items are objects.

dart
class User {
  final int id;
  final String name;
  
  User(this.id, this.name);
}

UserWidget(user, key: ObjectKey(user))

3. UniqueKey

Use when you need a unique key every time.

dart
RandomColorBox(key: UniqueKey())

4. GlobalKey

Access widget state from anywhere.

dart
final scaffoldKey = GlobalKey<ScaffoldState>();

Scaffold(
  key: scaffoldKey,
  body: ...,
)

// Access from anywhere
scaffoldKey.currentState?.openDrawer();

Complete Example: super(key: key)

dart
import 'package:flutter/material.dart';

// Base widget accepting key
class CustomButton extends StatelessWidget {
  final String text;
  final VoidCallback onPressed;
  
  // Accept key and pass to super
  const CustomButton({
    required this.text,
    required this.onPressed,
    Key? key,  // Optional key parameter
  }) : super(key: key);  // Pass to parent StatelessWidget
  
  
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: onPressed,
      child: Text(text),
    );
  }
}

// Usage with key
class MyScreen extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return Column(
      children: [
        CustomButton(
          text: 'Submit',
          onPressed: () {},
          key: Key('submit_button'),  // Assign key
        ),
        CustomButton(
          text: 'Cancel',
          onPressed: () {},
          key: Key('cancel_button'),
        ),
      ],
    );
  }
}

When Keys Matter

Problem: Widget State Loss

dart
class StatefulCounter extends StatefulWidget {
  const StatefulCounter({Key? key}) : super(key: key);
  
  
  _StatefulCounterState createState() => _StatefulCounterState();
}

class _StatefulCounterState extends State<StatefulCounter> {
  int count = 0;
  
  
  Widget build(BuildContext context) {
    return Text('$count');
  }
}

// Without keys - state lost when reordered
class CounterList extends StatelessWidget {
  final List<String> items;
  
  const CounterList(this.items);
  
  
  Widget build(BuildContext context) {
    return Column(
      children: items.map((item) {
        return StatefulCounter();  // ❌ No key - state lost
      }).toList(),
    );
  }
}

Solution: Add Keys

dart
class CounterList extends StatelessWidget {
  final List<String> items;
  
  const CounterList(this.items);
  
  
  Widget build(BuildContext context) {
    return Column(
      children: items.map((item) {
        return StatefulCounter(
          key: ValueKey(item),  // ✅ Key preserves state
        );
      }).toList(),
    );
  }
}

StatefulWidget with Key

dart
class Counter extends StatefulWidget {
  final String title;
  
  // Accept key and pass to super
  const Counter({
    required this.title,
    Key? key,
  }) : super(key: key);
  
  
  _CounterState createState() => _CounterState();
}

class _CounterState extends State<Counter> {
  int _count = 0;
  
  
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text(widget.title),
        Text('$_count'),
        ElevatedButton(
          onPressed: () => setState(() => _count++),
          child: Text('Increment'),
        ),
      ],
    );
  }
}

// Usage with key
Counter(
  title: 'My Counter',
  key: ValueKey('counter_1'),
)

GlobalKey Example

dart
import 'package:flutter/material.dart';

class FormScreen extends StatelessWidget {
  // Create GlobalKey
  final _formKey = GlobalKey<FormState>();
  
  
  Widget build(BuildContext context) {
    return Form(
      key: _formKey,  // Assign GlobalKey
      child: Column(
        children: [
          TextFormField(
            validator: (value) {
              if (value == null || value.isEmpty) {
                return 'Required';
              }
              return null;
            },
          ),
          ElevatedButton(
            onPressed: () {
              // Access form state via GlobalKey
              if (_formKey.currentState!.validate()) {
                print('Form is valid');
              }
            },
            child: Text('Submit'),
          ),
        ],
      ),
    );
  }
}

const Constructor Requirement

For

text
const
constructors, you must accept and pass the key.

dart
// ✅ Good - Accepts key
class MyWidget extends StatelessWidget {
  const MyWidget({Key? key}) : super(key: key);
  
  
  Widget build(BuildContext context) => Container();
}

// Usage
const MyWidget()  // Can use const

// ❌ Bad - No key parameter
class MyWidget extends StatelessWidget {
  const MyWidget();  // ❌ Cannot be fully const without key
  
  
  Widget build(BuildContext context) => Container();
}

Best Practices

Important: Always include

text
{Key? key}
in custom widget constructors

✅ Do

dart
// Good - Accept and pass key
class CustomWidget extends StatelessWidget {
  final String title;
  
  const CustomWidget({
    required this.title,
    Key? key,
  }) : super(key: key);
}

// Good - Use ValueKey for lists
ListView.builder(
  itemBuilder: (context, index) {
    return ListTile(
      key: ValueKey(items[index].id),
      title: Text(items[index].name),
    );
  },
)

❌ Don't

dart
// Bad - Missing key parameter
class CustomWidget extends StatelessWidget {
  final String title;
  
  const CustomWidget({required this.title});
  // Missing: Key? key, super(key: key)
}

// Bad - Using UniqueKey in build method

Widget build(BuildContext context) {
  return MyWidget(key: UniqueKey());  // ❌ Creates new key every build
}

Common Patterns

Pattern 1: Optional Key

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

// Usage
MyWidget()  // No key
MyWidget(key: ValueKey('my_widget'))  // With key

Pattern 2: Required Key

dart
class MyWidget extends StatelessWidget {
  const MyWidget({required Key key}) : super(key: key);
}

// Usage
MyWidget(key: ValueKey('my_widget'))  // Key required

Resources