Flutter arch vanilla example 笔记0

本文深入探讨了Flutter中状态管理的核心概念,包括如何通过提升状态到父组件来共享数据,使用回调函数更新状态,以及如何在测试中分离业务逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

README.md

vanilla example

The vanilla example uses only the core Widgets and Classes that Flutter provides out of the box to manage state. The most important of these: the StatefulWidget.

这个普通的例子只使用flutter提供的核心小部件和类,来管理状态。其中最重要的是状态小部件StatefulWidget

Key Concepts

关键概念

  • Share State by Lifting State Up - If two Widgets need access to the same state (aka data), "lift" the state up to a parent StatefulWidget that passes the state down to each child Widget that needs it.
  • Updating State with callbacks - To update state, pass a callback function from the Parent StatefulWidget to the child widgets.
  • Local persistence - The list of todos is serialized to JSON and stored as a file on disk whenever the State is updated.
  • Testing - Pull Business logic out of Widgets into Plain Old Dart Object (PODOs).
  • 通过向上提升状态来共享状态 - 如果两个小部件需要访问同一状态(即数据),则将状态向上提升到父状态小部件,它将状态向下传递给每个需要它的子小部件。
  • 使用回调更新状态 - 要更新状态,请将回调函数从父statefulwidget传递到子widget。
  • 本地持久化 - 当状态更新时,TODOS列表被序列化为JSON并存储为磁盘上的文件。
  • 测试 - 将业务逻辑从窗口小部件中拉入普通的旧DART对象(podos)。

Share State by Lifting State Up 通过提升状态共享状态

Let's start with a Simple Example. Say our app had only 1 Tab: The List of Todos Tab.

让我们从一个简单的例子开始。假设我们的应用只有一个标签页:Todos列表 标签页/选项卡。

+------------+
|            |
|   List     |
|   of       |
|   Todos    |
|   Tab      |
|            |
+------------+

Now, we add a sibling Widget: The Stats Tab! But wait, it needs access to the List of Todos so it can calculate how many of them are active and how many are complete. So how do we share that data?

现在,我们添加一个兄弟小部件:Stats统计Tab标签页/选项卡!但是,等等,它需要访问todo列表,以便计算其中有多少是活动的,有多少是完成的。那么我们如何共享这些数据呢?

It can be difficult for siblings to pass their state to each other. For example, say both Widgets were displayed side-by-side at the same time: How would Flutter know when to re-build the Stats Tab to reflect the latest count when the List of Todos changes?

对兄弟页之间来说,很难互相传递他们的状态。例如,假设两个小部件同时并排显示:flutter如何知道何时重新构建Stats选项卡以反映当前TODOS列表更改时的最新计数?

+-------------+                 +-------------+
|             |                 |             |
|             | Gimme dem Todos |             |
|   List of   | <-------------- +   Stats     |
|   Todos     |                 |   Tab       |
|   Tab       |    No. Mine.    |             |
|             + --------------> |             |
|             |                 |             |
+-------------+                 +-------------+

So how do we share state between these two sibling Widgets? Let's Lift the state up to a Parent Widget and pass it down to each child that needs it!

那么,我们如何在这两个兄弟小部件之间共享状态呢?让我们将状态提升到父窗口小部件,并将其传递给每个需要它的子窗口小部件!

     +-------------------------+
     |   Keeper of the Todos   |
     |    (StatefulWidget)     |
     +-----+--------------+----+
           |              |
+----------|--+       +---|---------+
|          v  |       |   v         |
|   List of   |       |   Stats     |
|   Todos     |       |   Tab       |
|             |       |             |
+-------------+       +-------------+

Now, when we change the List of Todos in the Keeper of the Todos widget, both children will reflect the updated State! This concept scales to an entire app. Any time you need to share State between Widgets or Routes, lift it up to a common parent Widget. Here's a diagram of what our app state actually looks like!

现在,当我们在todos的持有者的小部件中更改todos列表时,两个孩子都将反映更新后的状态!这个概念可以扩展到整个应用程序每当需要在小部件或路由之间共享状态时,将其提升到一个公共父小部件。这是我们的应用程序状态的图表!

   +------------------------------------------+
   |                                          |
   |      VanillaApp (StatefulWidget)         |
   |                                          |
   |    Manages List<Todo> and "isLoading"    |
   |                                          |
   +---------+---------------------------+----+
             |                           |
+------------|---------------+  +--------|--------+
|            v               |  |        v        |
|     Main Tabs Screen       |  | Add Todo Screen |
|        (Stateful)          |  |   (Stateless)   |
|                            |  |                 |
|   Manages current tab and  |  |                 |
|     Visibility filter      |  |                 |
|                            |  |                 |
| +----------+  +----------+ |  |                 |
| |          |  |          | |  |                 |
| | List     |  |          | |  |                 |
| | of       |  |  Stats   | |  |                 |
| | Todos    |  |  Tab     | |  |                 |
| | Tab      |  |          | |  |                 |
| +----+-----+  +----------+ |  |                 |
|      |                     |  |                 |
+------|---------------------+  +-----------------+
       |
+------|---------+
|      v         |
|                |
|  Todo Details  |
|  Screen        |
|                |
+------+---------+
       |
+------|---------+
|      v         |
|                |
|   Edit Todo    |
|   Screen       |
|                |
+----------------+

Careful Observers might note: We don't lift all state up to the parent in this pattern. Only the State that's shared! The Main Tabs Screen can handle which tab is currently active on its own, for example, because this state isn't relevant to other Widgets!

小心的观察者可能会注意到:在这个模式中,我们不会将所有状态提升到父状态。只有共享的状态!例如,主选项卡屏幕可以自行处理当前处于活动状态的选项卡,因为此状态与其他小部件无关!

Updating State with callbacks 使用回调函数更新状态

Ok, so now we have an idea of how to pass data down from parent to child, but how do we update the list of Todos from these different screens / Routes / Widgets?

好吧,现在我们有了一个如何将数据从父级传递到子级的想法,但是我们如何从这些不同的屏幕/路由/小部件更新to do列表呢?

We'll also pass callback functions from the parent to the children as well. These callback functions are responsible for updating the State at the Parent Widget and calling setState so Flutter knows it needs to rebuild!

我们还将将回调函数从父级传递给子级。这些回调函数负责更新父窗口小部件的状态,并调用setstate,因此flutter知道需要重建它!

In this app, we have a few callbacks we will pass down:

在这个应用程序中,我们有一些回调,我们将传递:

  1. AddTodo callback
  2. RemoveTodo Callback
  3. UpdateTodo Callback
  4. MarkAllComplete callback
  5. ClearComplete callback

In this app, we pass the AddTodo callback from our VanillaApp Widget to the Add Todo Screen. Now all our Add Todo Screen needs to do is call the AddTodo callback with a new Todo when a user finishes filling in the form. This will send the Todo up to the VanillaApp so it can handle how it adds the new todo to the list!

在这个应用程序中,我们将 AddTodo callback(添加待办事项回调)从我们的 VanillaApp 小部件传递到添加todo屏幕/页。现在,我们的添加待办事项屏幕需要做的就是在用户填写完表单后,带上一个新的待办事项,调用AddTodo callback(添加待办事项回调)。这会将这个todo发送到VanillaApp Widget,以便它可以处理如何将新的todo添加到列表中!

This demonstrates a core concept of State management in Flutter: Pass data and callback functions down from a parent to a child, and use invoke those callbacks in the Child to send data back up to the parent.

这演示了flutter中状态管理的核心概念:数据和回调函数从父级传递给子级,并使用调用子级中的回调将数据发送回父级

To make this concrete, Let's see how our callbacks flow in the app.

为了让这个更具体,让我们看看我们的回调如何在这个应用程序中流动

   +----------------------------------------------------+
   |                                                    |
   |      VanillaApp (StatefulWidget)                   |
   |                                                    |
   |    Manages List<Todo> and "isLoading"              |
   |                                             ^      |
   +---------+----------------------+------------|------+
             |                      |            |
             | UpdateTodo           | AddTodo    | Invoke AddTodo
             | RemoveTodo           |            | Callback, sending
             | MarkAllComplete      |            | Data up to the  
             | ClearComplete        |            | parent.
             |                      |            |
+------------|---------------+  +---|------------+-+
|            v               |  |   v              |
|     Main Tabs Screen       |  | Add Todo Screen  |
|        (Stateful)          |  |   (Stateless)    |
|                            |  |                  |
|   Manages current tab and  |  |                  |
|     Visibility filter      |  |                  |
|                            |  |                  |
| +----------+  +----------+ |  |                  |
| |          |  |          | |  |                  |
| | List     |  |          | |  |                  |
| | of       |  |  Stats   | |  |                  |
| | Todos    |  |  Tab     | |  |                  |
| | Tab      |  |          | |  |                  |
| +----+-----+  +----------+ |  |                  |
|      |                     |  |                  |
+------|---------------------+  +------------------+
       |
       | UpdateTodo
       | RemoveTodo
       |
+------|---------+
|      v         |
|                |
|  Todo Details  |
|  Screen        |
|                |
+------+---------+
       |
       | UpdateTodo
       |
+------|---------+
|      v         |
|                |
|   Edit Todo    |
|   Screen       |
|                |
+----------------+

Testing

There are a few Strategies for testing:

  1. Store state and the state mutations (methods) within a StatefulWidget
  2. Extract this State and logic out into a "Plain Old Dart Objects" (PODOs) and test those. The StatefulWidget can then delegate to this object.

So which should you choose? For View-related State: Option #1. For App State / Business Logic: Option #2.

While Option #1 works because Flutter provides a nice set of Widget testing utilities out of the box, Option #2 will generally prove easier to test because it has no Flutter dependencies and does not require you to test against a Widget tree, but simply against an Object.

有几个测试策略:

  1. StatefulWidget中存储状态和状态突变(方法)
  2. 将这个状态和逻辑提取到一个“普通的旧DART对象”(podos)中并测试这些对象。然后,StatefulWidget可以委托给这个对象。

那么你应该选择哪一个呢?对于视图相关的状态:选项1对于应用程序状态/业务逻辑:选项2。

虽然选项1起作用是因为flutter提供了一套现成的小部件测试实用程序,但选项2通常更容易测试,因为它没有flutter依赖性,不需要您针对小部件树进行测试,而只针对对象进行测试。

Addendum 附录

Since Flutter is quite similar to React with regards to State management, many of the resources on the React site are pertinent when thinking about State in flutter. In fact, the ideas in this example were lifted directly from the React site:

由于Flutter 关于状态管理方面与React 非常相似,因此在考虑Flutter 中的状态时,React 站点上的许多资源都是相关的。事实上,本例中的想法是直接从React 站点提出来的:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值