У меня есть REST API, который позволяет пользователю обновлять модель книги
GET /api/books.json # list of books
PUT /api/books/1.json # update the book with id=1
У меня есть соответствующие экраны для этих действий (экран указателя для списка книг; экран редактирования для редактирования сведений о книге) в моем приложении флаттера. При создании формы редактировать книгу,
- Я передаю объект книги в форму редактирования
- В форме редактирования я делаю копию объекта книги. Я создаю копию, а не редактирую исходный объект, чтобы гарантировать, что объект не будет изменен в случае сбоя обновления на сервере
- Если обновление выполнено успешно, я отображаю сообщение об ошибке.
Однако, когда я go возвращаюсь к представлению указателя, название книги остается прежним (так как этот объект не изменился). Кроме того, я обнаружил, что даже если я делаю изменения в исходном объекте, вместо того, чтобы делать копию, метод build
не вызывается, когда я go возвращаюсь. Мне интересно, есть ли шаблон, который я могу использовать для обновления этого объекта в приложении при успешном обновлении.
У меня есть следующие классы
class Book {
final int id;
final String title;
Book(this.id, this.title);
static Book fromJson(json) {
return Book(
json['id'],
json['title']);
}
Map<String, dynamic> toJson() => {
'title': title
};
Future<bool> update() {
var headers = {
'Content-Type': 'application/json'
};
return http
.put(
"$HOST/api/books/${id}.json",
headers: headers,
body: jsonEncode(this.toJson()),
)
.then((response) => response.statusCode == 200);
}
}
Вот представление индекса
class BooksIndex extends StatefulWidget {
static final tag = "books-index";
@override
_BooksIndexState createState() => _BooksIndexState();
}
class _BooksIndexState extends State<BooksIndex> {
final Future<http.Response> _getBooks = http.get("$HOST/api/books.json", headers: headers);
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: _getBooks,
builder: (context, snapshot) {
if (snapshot.hasData) {
var response = snapshot.data as http.Response;
if (response.statusCode == 200) {
List<dynamic> booksJson = jsonDecode(response.body);
List<Book> books = booksJson.map((bookJson) {
return Book.fromJson(bookJson);
}).toList();
return _buildMaterialApp(ListView.builder(
itemCount: books.length,
itemBuilder: (context, index) {
var book = books[index];
return ListTile(
title: Text(book.title),
onTap: () {
Navigator.push(context, MaterialPageRoute(
builder: (context) => BooksEdit(book: book)
));
},
);
},
));
} else {
return _buildMaterialApp(Text(
"An error occured while trying to retrieve the books. Status=${response.statusCode}"));
}
} else if (snapshot.hasError) {
return _buildMaterialApp(Text(
"Could not load books. Please check your internet connection."));
} else {
return _buildMaterialApp(Text("Loading"));
}
});
}
_buildMaterialApp(widget) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("Books"),
),
body: widget,
),
);
}
}
Вот форма редактирования
class BooksEdit extends StatelessWidget {
final Book book;
BooksEdit({Key key, @required this.book}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Edit ${book.title}"),
),
body: Column(
children: <Widget>[
BookForm(
book: book,
)
],
),
);
}
}
class BookForm extends StatefulWidget {
Book book;
BookForm({Key key, @required this.book}) : super(key: key);
@override
State<StatefulWidget> createState() {
return _BookFormState();
}
}
class _BookFormState extends State<BookForm> {
TextEditingController _titleField;
RaisedButton _submitBtn;
bool isError = false;
String formMessage = "";
@override
Widget build(BuildContext context) {
_titleField = TextEditingController(text: widget.book.title);
_submitBtn = RaisedButton(
child: Text(
"Update",
style: Theme
.of(context)
.textTheme
.button,
),
color: Theme
.of(context)
.primaryColor,
onPressed: () {
var book = Book(
widget.book.id,
_titleField.text
);
book.update().then((success) {
if (success) {
setState(() {
isError = false;
formMessage = "Successfully updated";
widget.book = book;
});
} else {
setState(() {
isError = true;
formMessage = "Book could not be updated";
});
}
}, onError: (error) {
setState(() {
isError = true;
formMessage =
"An unexpected error occured. It has been reported to the administrator.";
});
});
},
);
var formMessageColor = isError ? Colors.red : Colors.green;
return Form(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
formMessage,
style: TextStyle(color: formMessageColor),
),
TextFormField(
controller: _titleField,
),
_submitBtn
],
),
);
}
}
Здесь основной файл
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
final routes = <String, WidgetBuilder>{
'/': (context) => BooksIndex(),
};
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "BooksApp",
theme: ThemeData(primarySwatch: Colors.green),
routes: routes,
initialRoute: '/',
);
}
}
ТАКЖЕ , я новичок в Flutter. Поэтому я был бы признателен, если бы я получил какие-либо отзывы о других местах в моем коде, которые я могу улучшить.