I try to create a basic notes app to study about flutter and I do not quite understand how to notify my NotesContainer that the button has been pressed. I tried to create a ref to it but the adding function is in the state class that I'm not sure how to reach.

import 'package:flutter/material.dart';

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final NotesContainer Notes = new NotesContainer();
    return Scaffold(
      appBar: AppBar(
        centerTitle: true,
        title: Text('My Notes'),
        backgroundColor: Color.fromRGBO(223, 175, 117, 1),
        actions: <Widget>[
          IconButton(
            icon: Icon(Icons.add),
            onPressed: (){
              Notes.add()
            },
          )
        ],
      ),
      body: Notes
    );
  }
}

class NoteData{
  String title;
  String content;

  NoteData(this.title, this.content);
  NoteData.noContent(t){
    title = t;
    content ='';
  }
}

class NotesContainer extends StatefulWidget{
  @override

  State<StatefulWidget> createState(){
    return new _NotesContainer();
  }

}

class _NotesContainer extends State<NotesContainer>{
  final _notes = <NoteData>[new NoteData('title','thing to do'), new NoteData('title2','thing to do2')];

  void add({String title='1'}){ //just to test adding 
    setState(() {
       _notes.add(new NoteData.noContent(title));
    });
  }

  Widget build(BuildContext context){
    return _buildNotesContainer();
  }

  _buildNotesContainer(){

    return new ListView.separated(
      itemCount: _notes.length,
      separatorBuilder: (BuildContext context, int index) => Divider(),
      itemBuilder: (BuildContext context, int index) {
        return ListTile(
          title: Text(_notes[index].title), 
        );
      },
      padding: const EdgeInsets.all(10.0),
    );
  }
}

I guess the solution is somehow exposing the _function in the _NotesContainer via the stateful NotesContainer class. I wonder if there is a more elegant solution for this.

Thanks, Or


Solution 1: Tor-Martin Holen

I think it makes more sense delegating the responsibility of adding a element further up in the widget tree. I modified your code to show how this works.

However, if you eventually get a deep widget tree and the children widgets require the _notes list, then I would recommend that you look into using a Inherited widget and add the _notes list to it, so you can access it without passing the state around too much.

import 'package:flutter/material.dart';

// Note the name change
class NotesPage extends StatefulWidget {

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

class _NotesPageState extends State<NotesPage> {
  final List<NoteData> _notes = <NoteData>[NoteData('title','thing to do'), NoteData('title2','thing to do2')];

  void add({String title='1'}){ //just to test adding
    setState(() {
      _notes.add(NoteData.noContent(title));
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          centerTitle: true,
          title: Text('My Notes'),
          backgroundColor: Color.fromRGBO(223, 175, 117, 1),
          actions: <Widget>[
            IconButton(
              icon: Icon(Icons.add),
              onPressed: (){
                add();
              },
            )
          ],
        ),
        body: NotesContainer(notes: _notes)
    );
  }
}

class NoteData{
  String title;
  String content;

  NoteData(this.title, this.content);
  NoteData.noContent(t){
    title = t;
    content ='';
  }
}

class NotesContainer extends StatelessWidget{
  final List<NoteData> notes;

  const NotesContainer({Key key, this.notes}) : super(key: key);

  @override
  Widget build(BuildContext context){
    return ListView.separated(
      itemCount: notes.length,
      separatorBuilder: (BuildContext context, int index) => Divider(),
      itemBuilder: (BuildContext context, int index) {
        return ListTile(
          title: Text(notes[index].title),
        );
      },
      padding: const EdgeInsets.all(10.0),
    );
  }
}

Hope it helps :-)