How to reset a flutter Page (Widget) to initial state(state when the app was first Built)

Viewed 19450

Let's say I have a few sliders and switches on my page, I change their state and modify them, I understand that we do setState to show the changed state of the widget tree and rebuild it, but I would like to know if there's a way to undo all those changes and go back to the initial state (state the app was when it was first built)?

7 Answers

If you want to do things out of the box

enter image description here


Short answer:

Use any of the below:

Navigator.pushReplacementNamed(context, '/currentRoute');
Navigator.popAndPushNamed(context, '/currentRoute');

Long answer:

void main() => runApp(MaterialApp(home: DummyWidget()));

class DummyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) => HomePage();
}

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  bool _enabled = false; // For Switch
  double _value = 0; // For Slider

  // This is the trick!
  void _reset() {
    Navigator.pushReplacement(
      context,
      PageRouteBuilder(
        transitionDuration: Duration.zero,
        pageBuilder: (_, __, ___) => DummyWidget(),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
          Switch(
            value: _enabled,
            onChanged: (newValue) => setState(() => _enabled = newValue),
          ),
          Slider(
            value: _value,
            onChanged: (newValue) => setState(() => _value = newValue),
          ),
          FlatButton(
            onPressed: _reset,
            child: Text('RESET'),
          ),
        ],
      ),
    );
  }
}

A better approach might be with keys. Here's the key approach

A simple trick would be to pop and push with the same route. Like this:

Navigator.popAndPushNamed(context, "same_route");

Screenshot:

enter image description here


Using key to change the state.

void main() => runApp(MaterialApp(home: HomePage()));

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  int _count = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: KeyedSubtree(
        key: ValueKey<int>(_count),
        child: Column(
          children: [
            MainPage(),
            FlatButton(
              onPressed: () => setState(() => ++_count),
              child: Text('RESET'),
            )
          ],
        ),
      ),
    );
  }
}

class MainPage extends StatefulWidget {
  @override
  _MainPageState createState() => _MainPageState();
}

class _MainPageState extends State<MainPage> {
  bool _enabled = false; // For Switch
  double _value = 0; // For Slider.

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Switch(
          value: _enabled,
          onChanged: (newValue) => setState(() => _enabled = newValue),
        ),
        Slider(
          value: _value,
          onChanged: (newValue) => setState(() => _value = newValue),
        ),
      ],
    );
  }
}

Here is one way of many to reset to the initial data

enter image description here

import 'package:flutter/material.dart';

List<String> initialData = ['First', 'Second', 'Third'];

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData.dark(),
      home: Example(),
    );
  }
}

class Example extends StatefulWidget {
  @override
  _ExampleState createState() => _ExampleState();
}

class _ExampleState extends State<Example> {
  List<String> items = [];

  @override
  void initState() {
    fillInitialData();
    super.initState();
  }

  fillInitialData() {
    items.addAll(initialData);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Example')),
      body: Column(
        children: <Widget>[
          Expanded(
            child: ListView.builder(
              itemCount: items.length,
              itemBuilder: (context, index) {
                return Card(
                  child: Padding(
                    padding: EdgeInsets.all(16.0),
                    child: Text(items[index]),
                  ),
                );
              },
            ),
          ),
          Row(
            children: <Widget>[
              FlatButton(
                onPressed: () {
                  setState(() {
                    items.add('A new item');
                  });
                },
                child: Text('Add an item'),
              ),
              FlatButton(
                onPressed: () {
                  setState(() {
                    items.clear();
                    fillInitialData();
                  });
                },
                child: Text('Reset'),
              ),
            ],
          ),
        ],
      ),
    );
  }
}

Screenshot:

enter image description here

Full Code:

void main() {
  runApp(
    MaterialApp(
      // Passing initial values
      home: HomePage(enabled: false, value: 0),
    ),
  );
}

class HomePage extends StatefulWidget {
  final bool enabled;
  final double value;

  HomePage({this.enabled = false, this.value = 0});

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

class _HomePageState extends State<HomePage> {
  bool _initialEnabled, _enabled; // For Switches
  double _initialValue, _value; // For Sliders

  @override
  void initState() {
    super.initState();

    // Assign them once (initial data)
    _initialEnabled ??= widget.enabled;
    _initialValue ??= widget.value;

    // These values can be changed by respective widgets
    _enabled = _initialEnabled;
    _value = _initialValue;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Padding(
        padding: const EdgeInsets.all(20),
        child: Column(
          children: [
            Switch(
              value: _enabled,
              onChanged: (value) => setState(() => _enabled = value),
            ),
            Slider(
              value: _value,
              onChanged: (value) => setState(() => _value = value),
            ),
            RaisedButton(
              onPressed: () {
                setState(() {
                  // Resetting the values to initial ones which were passed
                  _enabled = _initialEnabled;
                  _value = _initialValue;
                });
              },
              child: Text('RESET'),
            ),
          ],
        ),
      ),
    );
  }
}

There are a couple of age-old design patterns that might be useful in this situation. Having a reset option is cool, but what's cooler is undo.

See how the Command and Memento patterns can be implemented in Flutter with these tutorials: Command | Memento

You can call YourStateClass.initState() to revert to its original initialized state.

Also make sure that when you construct your state, you will want to initialize all of your variables in the void initState() function.

ex.

class FooState extends State<Foo> { 
    int someVariable;

    @override
    void initState() {
        someVariable = 0;
    }
}

You need to have all of your variables assigned a value in the initState() function in order for this to work.

For more info check out the docs at: https://api.flutter.dev/flutter/widgets/State/initState.html

Related