Flutter数据变换插件flutter_mutation的使用

发布于 1周前 作者 zlyuanteng 来自 Flutter

Flutter数据变换插件flutter_mutation的使用

特性

  • 使用hook轻松处理Flutter中的异步状态

开始使用

pubspec.yaml文件中添加依赖:

dependencies:
  flutter_mutation: ^latest

使用示例

异步获取

以下示例展示了如何使用flutter_mutation进行异步数据获取。

class GettingStartedPage extends HookWidget {
  const GettingStartedPage({super.key});

  static MaterialPageRoute createRoute() {
    return MaterialPageRoute(builder: (context) {
      return const GettingStartedPage();
    });
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("getting started page"),
      ),
      body: Center(
        child: Stack(
          alignment: Alignment.center,
          children: [
            HookBuilder(builder: (context) {
              final loading = useMutationLoading(keyOf: "get");
              return Visibility(
                  visible: loading, child: const CircularProgressIndicator());
            }),
            Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                HookBuilder(builder: (context) {
                  final data = useMutationLoading(keyOf: "get");
                  return Text("loading:$data");
                }),
                HookBuilder(builder: (context) {
                  final data = useMutationData(keyOf: "get");
                  return Text("data:$data");
                }),
                HookBuilder(builder: (context) {
                  final data = useMutationInitialized(keyOf: "get");
                  return Text("initialized:$data");
                }),
                HookBuilder(builder: (context) {
                  final data = useMutationError(keyOf: "get");
                  return Text("error:$data");
                }),
                TextButton(
                    onPressed: () async {
                      MutationKey.of("get").mutate(GettingStartedApi.get());
                    },
                    child: const Text("mutate")),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

分页

以下示例展示了如何使用flutter_mutation实现分页功能。

class PaginationPage extends HookWidget {
  const PaginationPage({super.key});

  static MaterialPageRoute createRoute() {
    return MaterialPageRoute(builder: (context) {
      return const PaginationPage();
    });
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    print("cache:${MutationCache.instance}");
    final mutationKey = useMutationKey<PaginationResponse>();
    final onPressMore = useCallback(() {
      PaginationApi.getList(mutationKey.data?.nextPageKey)
          .mutate(mutationKey, append: true);
    }, []);
    final onRefresh = useCallback(() async {
      return PaginationApi.getList().mutate(mutationKey);
    }, []);
    return Scaffold(
      appBar: AppBar(
        title: const Text("pagination page"),
      ),
      body: RefreshIndicator(
        onRefresh: onRefresh,
        child: HookBuilder(builder: (context) {
          final dataList = useMutationDataList(key: mutationKey);
          final loading = useMutationLoading(
              key: mutationKey, lazyInitialData: PaginationApi.getList);
          final list = useMemoized(
                  () => dataList.expand((element) => element.list).toList(),
              [dataList]);
          return ListView.builder(
            itemCount: list.length + 1,
            itemBuilder: (context, index) {
              if (index == list.length) {
                return TextButton(
                    onPressed: loading ? null : onPressMore,
                    child: loading
                        ? const Text("Loading...")
                        : const Text("More"));
              }
              final item = list[index];
              return ListTile(
                title: Text(item),
              );
            },
          );
        }),
      ),
    );
  }
}

缓存

以下示例展示了如何使用flutter_mutation进行缓存管理。

final MutationKey<CachingResponse> cacheKey = MutationKey.of("aa");

class CachingPage extends HookWidget {
  const CachingPage({super.key});

  static MaterialPageRoute createRoute() {
    return MaterialPageRoute(builder: (context) {
      return const CachingPage();
    });
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    print("cache:${MutationCache.instance}");
    useEffect(() {
      return cacheKey.observe(onClose: (mutation) {
        print("closed:$mutation");
      });
    }, [cacheKey]);
    final onPressRefresh = useCallback(() async {
      await CachingApi.get().mutate(cacheKey);
    }, []);
    return Scaffold(
      appBar: AppBar(
        title: const Text("caching page"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            HookBuilder(
                key: UniqueKey(),
                builder: (context) {
                  final loading = useMutationLoading(key: cacheKey);
                  return loading
                      ? const Text("Loading...")
                      : const Text("complete");
                }),
            HookBuilder(builder: (context) {
              final data = useMutationData(
                  key: cacheKey, lazyInitialData: CachingApi.get);
              return Text("title:${data?.title}");
            }),
            TextButton(onPressed: onPressRefresh, child: const Text("refresh")),
            TextButton(
                onPressed: () {
                  Navigator.of(context).push(CachingNextPage.createRoute());
                },
                child: const Text("next"))
          ],
        ),
      ),
    );
  }
}

class CachingNextPage extends HookWidget {
  const CachingNextPage({super.key});

  static MaterialPageRoute createRoute() {
    return MaterialPageRoute(builder: (context) {
      return const CachingNextPage();
    });
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    final onPressRefresh = useCallback(() async {
      await CachingApi.get().mutate(cacheKey);
    }, []);
    return Scaffold(
      appBar: AppBar(
        title: const Text("caching next page"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            HookBuilder(builder: (context) {
              final loading = useMutationLoading(key: cacheKey);
              return loading
                  ? const Text("Loading...")
                  : const Text("complete");
            }),
            HookBuilder(builder: (context) {
              final data = useMutationData(
                  lazyInitialData: CachingApi.get, key: cacheKey);
              return Text(
                  "nickname: ${data?.nickname}\ncontents: ${data?.contents}");
            }),
            TextButton(onPressed: onPressRefresh, child: const Text("refresh"))
          ],
        ),
      ),
    );
  }
}

全局状态

以下示例展示了如何使用flutter_mutation管理全局状态。

class GlobalStateMutations {
  static final authTokenKey = MutationKey<String>().retain(onOpen: (mutation) {
    print("onOpen:$mutation");
  }, onUpdateData: (data, {before}) {
    print("onUpdateData:$data, $before");
  });
}

class GlobalStatePage extends HookWidget {
  const GlobalStatePage({super.key});

  static MaterialPageRoute createRoute() {
    return MaterialPageRoute(builder: (context) {
      return const GlobalStatePage();
    });
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    print("cache:${MutationCache.instance}");
    final onPressLogin = useCallback(() {
      GlobalStateApi.postLogin().mutate(GlobalStateMutations.authTokenKey);
    }, []);
    final onPressClear = useCallback(() {
      GlobalStateMutations.authTokenKey.clear();
    }, []);
    return Scaffold(
      appBar: AppBar(
        title: const Text("global state page"),
      ),
      body: Center(
        child: Stack(
          alignment: Alignment.center,
          children: [
            HookBuilder(builder: (context) {
              final loading =
              useMutationLoading(key: GlobalStateMutations.authTokenKey);
              return Visibility(
                  visible: loading, child: const CircularProgressIndicator());
            }),
            Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                HookBuilder(builder: (context) {
                  final data =
                  useMutationData(key: GlobalStateMutations.authTokenKey);
                  return Text("authToken:$data");
                }),
                TextButton(onPressed: onPressLogin, child: const Text("login")),
                TextButton(onPressed: onPressClear, child: const Text("clear"))
              ],
            ),
          ],
        ),
      ),
    );
  }
}

懒加载

以下示例展示了如何使用flutter_mutation进行懒加载操作。

final MutationKey<String> lazyMutateKey =
    MutationKey<String>().retain(onUpdateData: (data, {before}) {
  print("onUpdateData:$data");
}, onUpdateLoading: (loading) {
  print("onUpdateLoading:$loading");
});

class LazyMutatePage extends HookWidget {
  const LazyMutatePage({super.key});

  static MaterialPageRoute createRoute() {
    return MaterialPageRoute(builder: (context) {
      return const LazyMutatePage();
    });
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    print("cache:${MutationCache.instance}");
    return Scaffold(
      appBar: AppBar(
        title: const Text("lazy mutate page"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            HookBuilder(builder: (context) {
              final loading = useMutationLoading<String>(key: lazyMutateKey);
              return loading
                  ? const Text("Loading...")
                  : const Text("complete");
            }),
            HookBuilder(builder: (context) {
              final data = useMutationData(
                  key: lazyMutateKey, lazyInitialData: LazyMutateApi.get);
              return Text("data:$data");
            }),
            TextButton(
                onPressed: () {
                  LazyMutateApi.get().mutate(lazyMutateKey);
                },
                child: const Text("refresh")),
            TextButton(
                onPressed: () {
                  lazyMutateNextKey.lazyMutate(LazyMutateApi.get2);
                },
                child: const Text("lazyMutateNext")),
            TextButton(
                onPressed: () {
                  Navigator.of(context).push(LazyMutateNextPage.createRoute());
                },
                child: const Text("next"))
          ],
        ),
      ),
    );
  }
}

final MutationKey<String> lazyMutateNextKey =
MutationKey<String>().retain(onUpdateData: (data, {before}) {
  print("onUpdateData:$data");
}, onUpdateLoading: (loading) {
  print("onUpdateLoading:$loading");
});

class LazyMutateNextPage extends HookWidget {
  const LazyMutateNextPage({super.key});

  static MaterialPageRoute createRoute() {
    return MaterialPageRoute(builder: (context) {
      return const LazyMutateNextPage();
    });
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("lazy mutate next page"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            HookBuilder(builder: (context) {
              final loading = useMutationLoading(key: lazyMutateNextKey);
              return loading
                  ? const Text("Loading...")
                  : const Text("complete");
            }),
            HookBuilder(builder: (context) {
              final data = useMutationData(key: lazyMutateNextKey);
              return Text("data: $data");
            }),
            TextButton(
                onPressed: () {
                  lazyMutateNextKey.lazyMutate(LazyMutateApi.get2);
                },
                child: const Text("lazyMutate")),
            TextButton(
                onPressed: () {
                  lazyMutateKey.lazyMutate(LazyMutateApi.get);
                },
                child: const Text("lazyMutateBefore"))
          ],
        ),
      ),
    );
  }
}

更多关于Flutter数据变换插件flutter_mutation的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter数据变换插件flutter_mutation的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,flutter_mutation 是一个用于在 Flutter 中进行数据变换的插件。虽然它不是一个官方或广泛使用的插件(请注意,由于插件的流行度和维护状态可能会随时间变化,以下信息可能需要根据实际情况调整),但假设它提供了类似数据映射、转换等功能,我们可以基于常见的数据变换需求给出一个示例。

通常,数据变换可能涉及将 JSON 数据映射到 Dart 模型、数据过滤、数据格式化等操作。虽然 flutter_mutation 的具体 API 可能有所不同,但我们可以模拟一个类似功能的实现。

以下是一个假设的 flutter_mutation 使用示例,这里我们将使用自定义的代码来模拟数据变换的过程,因为实际的 flutter_mutation 插件细节可能未知。

示例:将 JSON 数据映射到 Dart 模型并进行变换

1. 定义 Dart 模型

首先,我们定义一个 Dart 模型类来映射 JSON 数据。

class User {
  String name;
  int age;
  String email;

  User({required this.name, required this.age, required this.email});

  // 从 JSON 数据创建 User 实例的工厂方法
  factory User.fromJson(Map<String, dynamic> json) {
    return User(
      name: json['name'] as String,
      age: json['age'] as int,
      email: json['email'] as String,
    );
  }

  // 将 User 实例转换为 JSON 数据
  Map<String, dynamic> toJson() {
    return {
      'name': name,
      'age': age,
      'email': email,
    };
  }
}

2. 数据变换逻辑(模拟 flutter_mutation 的功能)

接下来,我们编写一些数据变换逻辑,比如将用户列表中的年龄增加一岁,或者将电子邮件地址格式化为小写。

List<User> transformUserList(List<User> users) {
  return users.map((user) {
    // 增加年龄
    int newAge = user.age + 1;
    // 格式化电子邮件地址
    String formattedEmail = user.email.toLowerCase();

    // 返回一个新的 User 实例,包含变换后的数据
    return User(
      name: user.name,
      age: newAge,
      email: formattedEmail,
    );
  }).toList();
}

3. 使用变换逻辑

最后,我们模拟从某处获取 JSON 数据,将其转换为 Dart 模型列表,并应用变换逻辑。

void main() {
  // 假设这是从服务器获取的原始 JSON 数据
  String jsonData = '''
  [
    {"name": "Alice", "age": 30, "email": "Alice@example.COM"},
    {"name": "Bob", "age": 25, "email": "BOB@example.com"}
  ]
  ''';

  // 将 JSON 数据转换为 List<Map<String, dynamic>>
  List<dynamic> jsonList = jsonDecode(jsonData);

  // 将 List<Map<String, dynamic>> 转换为 List<User>
  List<User> userList = jsonList.map((json) => User.fromJson(json as Map<String, dynamic>)).toList();

  // 应用数据变换逻辑
  List<User> transformedUserList = transformUserList(userList);

  // 输出变换后的数据
  transformedUserList.forEach((user) {
    print('Name: ${user.name}, Age: ${user.age}, Email: ${user.email}');
  });
}

总结

虽然这个示例没有直接使用假设的 flutter_mutation 插件,但它展示了在 Flutter 中进行数据变换的常见方法,包括定义数据模型、编写变换逻辑以及应用这些逻辑。如果 flutter_mutation 插件确实存在并具有类似功能,其使用方式可能会更加简洁或高效,但基本原理是相似的。

请注意,实际开发中应参考 flutter_mutation(如果可用)的官方文档和 API 以获取准确的使用方法和最佳实践。

回到顶部