gpt4 book ai didi

rest - 更新资源或模型对象时如何在不同的屏幕/小工具之间进行同步?

转载 作者:行者123 更新时间:2023-12-03 04:55:39 25 4
gpt4 key购买 nike

我有一个REST API,允许用户更新Book模型

GET /api/books.json # list of books
PUT /api/books/1.json # update the book with id=1

在flutter应用程序中,我有对应于这些操作的屏幕(用于列出书的索引屏幕;用于编辑书详细信息的编辑屏幕)。创建表单时,编辑一本书,
  • 我将Book对象传递给Edit表单
  • 在“编辑”表单中,我复制了book对象。我创建一个副本,并且不编辑原始对象,以确保如果服务器
  • 上的更新失败,则该对象不会更改
  • 如果更新成功,则会显示一条错误消息。

  • 但是,当我返回到“索引” View 时,书名仍然相同(因为此对象未更改)。另外,我发现即使我对原始对象进行更改,而不是进行复制,当我“返回”时也不会调用 build方法。我想知道是否有一种模式可以成功更新整个应用程序中的对象。

    我有以下类(class)
    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);
    }
    }

    这是索引 View
    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的新手。因此,如果我对代码中可以改进的其他地方有任何反馈,我将不胜感激。

    最佳答案

    您可以在下面复制粘贴运行完整代码
    我使用固定的json字符串来模拟http,当调用update时,仅更改json字符串
    您还可以引用官方示例https://flutter.dev/docs/cookbook/networking/fetch-data
    步骤1:您可以await Navigator.push并在setState之后执行await以刷新BooksIndex步骤2:将解析JSON逻辑移至getBooks程式码片段

    return ListTile(
    title: Text(book.title),
    onTap: () async {
    await Navigator.push(
    context,
    MaterialPageRoute(
    builder: (context) => BooksEdit(book: book)));
    setState(() {});
    },

    Future<List<Book>> httpGetBooks() async {
    print("httpGetBooks");
    var response = http.Response(jsonString, 200);
    if (response.statusCode == 200) {
    print("200");
    List<dynamic> booksJson = jsonDecode(response.body);
    List<Book> books = booksJson.map((bookJson) {
    return Book.fromJson(bookJson);
    }).toList();
    print(books[1].title.toString());
    return books;
    }
    }

    工作演示

    enter image description here

    完整的代码
    import 'package:flutter/material.dart';
    import 'package:http/http.dart' as http;
    import 'dart:convert';

    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: '/',
    );
    }
    }

    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
    ],
    ),
    );
    }
    }

    class BooksIndex extends StatefulWidget {
    static final tag = "books-index";

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

    String jsonString = '''
    [{
    "id" : 1,
    "title" : "t"
    }
    ,
    {
    "id" : 2,
    "title" : "t1"
    }
    ]
    ''';

    class _BooksIndexState extends State<BooksIndex> {
    Future<List<Book>> httpGetBooks() async {
    print("httpGetBooks");
    var response = http.Response(jsonString, 200);
    if (response.statusCode == 200) {
    print("200");
    List<dynamic> booksJson = jsonDecode(response.body);
    List<Book> books = booksJson.map((bookJson) {
    return Book.fromJson(bookJson);
    }).toList();
    print(books[1].title.toString());
    return books;
    }
    }

    @override
    void initState() {
    // TODO: implement initState
    super.initState();
    }

    @override
    Widget build(BuildContext context) {
    print("build ${jsonString}");
    return FutureBuilder<List<Book>>(
    future: httpGetBooks(),
    builder: (context, snapshot) {
    if (snapshot.hasData) {
    print("hasData");
    return _buildMaterialApp(ListView.builder(
    itemCount: snapshot.data.length,
    itemBuilder: (context, index) {
    var book = snapshot.data[index];
    print(book.title);
    return ListTile(
    title: Text(book.title),
    onTap: () async {
    await Navigator.push(
    context,
    MaterialPageRoute(
    builder: (context) => BooksEdit(book: book)));
    setState(() {});
    },
    );
    },
    ));
    } 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 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() {
    print("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);*/

    jsonString = '''
    [{
    "id" : 1,
    "title" : "t"
    }
    ,
    {
    "id" : 2,
    "title" : "test"
    }
    ]
    ''';
    return Future.value(true);
    }
    }


    setState(() {

    });

    },
    );

    关于rest - 更新资源或模型对象时如何在不同的屏幕/小工具之间进行同步?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60647426/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com