# Flutter Model の基本

モデルは、アプリケーションのデータを表現し、データの操作や管理を容易にするために使用されます。

 







 








 








class User {
  final int id;
  final String name;
  final String email;

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

  // JSONからUserオブジェクトを生成するファクトリコンストラクタ
  factory User.fromJson(Map<String, dynamic> json) {
    return User(
      id: json['id'] is String ? int.parse(json['id']) : json['id'] as int,
      name: json['name'] as String,
      email: json['email'] as String,
    );
  }

  // UserオブジェクトをJSONに変換するメソッド
  Map<String, dynamic> toJson() {
    return {
      'id': id,
      'name': name,
      'email': email,
    };
  }
}

# JSON からモデルへの変換

API などから取得した JSON データをモデルに変換するには、上記のfromJsonファクトリコンストラクタを使用します。

void main() {
  // サンプルJSONデータ
  Map<String, dynamic> json = {
    'id': 123,
    'name': 'John Doe',
    'email': 'john.doe@example.com',
  };

  // JSONデータからUserオブジェクトを生成
  User user = User.fromJson(json);

  print('ID: ${user.id}');
  print('Name: ${user.name}');
  print('Email: ${user.email}');
}

# モデルから JSON への変換

モデルを JSON 形式で保存したり送信したりするには、toJsonメソッドを使用します。

void main() {
  // Userオブジェクトを生成
  User user = User(id: 123, name: 'John Doe', email: 'john.doe@example.com');

  // UserオブジェクトをJSON形式に変換
  Map<String, dynamic> json = user.toJson();

  print('JSON: $json');
}

final キーワードについて

  • 変数が初期化された後に変更されないことを保証
  • コンストラクタ内で初期化する際に使用することをおすすめ

データの不変性を保証することで、予期せぬバグの発生を防ぐことができます。final を積極に使うべきです。

# ディレクトリ構造

lib/
|-- models/
|   |-- user.dart
|-- screens/
|   |-- home_screen.dart
|-- services/
|   |-- api_service.dart
|   |-- user_service.dart
|-- widgets/
|   |-- user_list.dart
|-- main.dart

lib/models/ディレクトリにモデルクラスを配置することがおすすめです。
user.dartの場合、lib/models/user.dartになりますね。

# UserList 作成してみる

StatelessWidgetを使用して、User モデルのリストを表示する UserList ウィジェットを作成

# API ファイル作成

// lib/services/api_service.dart
import 'dart:convert';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:http/http.dart' as http;

class ApiService {
  final String baseUrl = dotenv.env['API_BASE_URL'] ?? '';

  Future<dynamic> getRequest(String endpoint) async {
    final response = await http.get(Uri.parse('$baseUrl$endpoint'));
    if (response.statusCode == 200) {
      return jsonDecode(response.body);
    } else {
      throw Exception('Failed to load data');
    }
  }

  Future<dynamic> postRequest(String endpoint, Map<String, dynamic> data) async {
    final response = await http.post(
      Uri.parse('$baseUrl$endpoint'),
      headers: {'Content-Type': 'application/json'},
      body: jsonEncode(data),
    );
    if (response.statusCode == 200) {
      return jsonDecode(response.body);
    } else {
      throw Exception('Failed to post data');
    }
  }

  Future<dynamic> putRequest(String endpoint, Map<String, dynamic> data) async {
    final response = await http.put(
      Uri.parse('$baseUrl$endpoint'),
      headers: {'Content-Type': 'application/json'},
      body: jsonEncode(data),
    );
    if (response.statusCode == 200) {
      return jsonDecode(response.body);
    } else {
      throw Exception('Failed to update data');
    }
  }

  Future<dynamic> deleteRequest(String endpoint) async {
    final response = await http.delete(Uri.parse('$baseUrl$endpoint'));
    if (response.statusCode == 200) {
      return jsonDecode(response.body);
    } else {
      throw Exception('Failed to delete data');
    }
  }
}
// lib/services/user_service.dart
import 'package:my_app/models/user.dart';
import 'api_service.dart';

class UserService {
  final ApiService apiService;

  UserService({required this.apiService});

  Future<List<User>> fetchUsers() async {
    final data = await apiService.getRequest('/users');
    return (data as List).map((json) => User.fromJson(json)).toList();
  }

  Future<User> updateUser(String id, Map<String, dynamic> data) async {
    final response = await apiService.putRequest('/users/$id', data);
    return User.fromJson(response);
  }

  Future<void> deleteUser(String id) async {
    await apiService.deleteRequest('/users/$id');
  }
}

# UserList ウィジェットの作成

// lib/widgets/user_list.dart
import 'package:flutter/material.dart';
import 'package:my_app/models/user.dart';
import 'package:my_app/services/user_service.dart';

class UserList extends StatelessWidget {
  final List<User> users;
  final UserService userService;

  const UserList({super.key, required this.users, required this.userService});

  
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: users.length,
      itemBuilder: (context, index) {
        return ListTile(
          title: Text(users[index].name),
          subtitle: Text(users[index].email),
          trailing: Row(
            mainAxisSize: MainAxisSize.min,
            children: [
              IconButton(
                icon: const Icon(Icons.edit),
                onPressed: () {
                },
              ),
              IconButton(
                icon: const Icon(Icons.delete),
                onPressed: () async {
                  await userService.deleteUser(users[index].id);
                },
              ),
            ],
          ),
        );
      },
    );
  }
}

# UserList ウィジェットの使用してホームスクリーンを作成

// lib/screens/home_screen.dart
import 'package:flutter/material.dart';
import 'package:my_app/models/user.dart';
import 'package:my_app/services/api_service.dart';
import 'package:my_app/services/user_service.dart';
import 'package:my_app/widgets/user_list.dart';

class HomeScreen extends StatefulWidget {
  
  HomeScreenState createState() => HomeScreenState();
}

class HomeScreenState extends State<HomeScreen> {
  late Future<List<User>> futureUsers;
  late UserService userService;

  
  void initState() {
    super.initState();
    userService = UserService(apiService: ApiService());
    futureUsers = userService.fetchUsers();
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('User List'),
      ),
      body: FutureBuilder<List<User>>(
        future: futureUsers,
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting) {
            return Center(child: CircularProgressIndicator());
          } else if (snapshot.hasError) {
            return Center(child: Text('Failed to load users'));
          } else if (!snapshot.hasData || snapshot.data!.isEmpty) {
            return Center(child: Text('No users found'));
          } else {
            return UserList(users: snapshot.data!, userService: userService);
          }
        },
      ),
    );
  }
}

# main dart 修正

// lib/main.dart
import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:my_app/screens/home_screen.dart';

void main() async {
  await dotenv.load(fileName: ".env");
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'Flutter Demo',
      home: HomeScreen(),
    );
  }
}
2024-06-04
  • flutter