🐧
Joke API × Riverpodで学ぶFlutter入門|素晴らしいジョークで状態管理を2%理解する
Flutter × Riverpod の学習として、外部APIを使ったアプリを作ってみました
Riverpodを優しく理解するために作成しているので主にリバーポッド部分の解説になります。
使用した
-Flutter
-Riverpod(FutureProvider)
-Dio(API通信)
-Official Joke API(https://official-joke-api.appspot.com)
-Sourcetree(Git管理)
📦 jokeapiriverpod
Flutter + Riverpod を使ったジョークアプリです。
GitHub: yoichi4141/jokeapiriverpod
アプリの内容
-ジョークを1つ取得して表示
-「もっと💩」ボタンで再取得
コード解説 🔍
-モデルの定義(Jokeクラス)
-jokeProvider(FutureProviderで非同期取得)
-フィルター機能(containsPoop関数とwhileループ)
-UI(ConsumerWidget)
完成イメージ
面白すぎるジョークが展開される
コード↓
main:
//main.dart
import 'package:flutter/material.dart';
import 'package:dio/dio.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:fluttercook/providers/joke_provider.dart';
void main() {
runApp(const ProviderScope(child: MyApp()));
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
Widget build(BuildContext context) {
return const MaterialApp(home: JokeScreen());
}
}
class JokeScreen extends ConsumerWidget {
const JokeScreen({super.key});
Widget build(BuildContext context, WidgetRef ref) {
final jokeAsync = ref.watch(jokeProvider);
return Scaffold(
appBar: AppBar(title: const Text('💩ジョーク with Riverpod')),
body: jokeAsync.when(
loading: () => const Center(child: CircularProgressIndicator()),
error:
(err, _) =>
Center(child: Text('ohhhhhh!!!shiiiit!!!!!!error!!!!!!!!')),
data:
(joke) => Padding(
padding: const EdgeInsets.all(24),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
joke.setup,
style: const TextStyle(fontSize: 20),
textAlign: TextAlign.center,
),
const SizedBox(height: 20),
Text(
joke.punchline,
style: const TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 40),
ElevatedButton(
onPressed: () => ref.refresh(jokeProvider),
child: const Text('もっと💩'),
),
],
),
),
),
);
}
}
model:
//joke.dart
class Joke {
final String setup;
final String punchline;
Joke({required this.setup, required this.punchline});
factory Joke.fromJson(Map<String, dynamic> json) {
return Joke(setup: json['setup'], punchline: json['punchline']);
}
}
provider:
//joke_provider.dart
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:dio/dio.dart';
import 'package:fluttercook/model/joke.dart';
//Dioクライアント
final dioProvider = Provider((ref) => Dio());
//FutureProviderでジョーク取得
final jokeProvider = FutureProvider<Joke>((ref) async {
final dio = ref.watch(dioProvider);
final response = await dio.get(
'https://official-joke-api.appspot.com/jokes/random',
);
return Joke.fromJson(response.data);
});
覚えておきたいこと
・refはRiverpodによって内部で管理されており、各プロバイダーに自動で渡される特別な引数
・「refに格納する」ではなく→「refで参照する」「refで依存を定義する(宣言する)」
イメージ:
refは「テレビのリモコン」
dioProvider は「チャンネル(Dio)」
ref.watch(dioProvider) は「そのチャンネルを見る操作」
でもリモコン自体に番組が格納されてるわけじゃない
Discussion