Menu
CoddyTech

בנאי fromJson

חלק מהיחידה נתונים ורשת במסלול ה-Flutter של Coddy. שיעור 17 מתוך 27.

קריאה של user['name'] as String בכל המסכים שלך הופכת למסורבלת, ושגיאת הקלדה אחת במפתח גורמת לשבירת הקוד. הפתרון המקובל הוא מחלקה לנתונים, עם בנאי אחד שמכיר את JSON. הוא נקרא fromJson:

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

  final String name;
  final int age;

  factory User.fromJson(Map<String, dynamic> json) {
    return User(
      name: json['name'] as String,
      age: json['age'] as int,
    );
  }
}

User.fromJson הוא בנאי בעל שם, דרך נוספת ליצור User. המילה factory מאפשרת לבנאי להריץ קוד ולהחזיר את האובייקט שהוא יוצר באמצעות return. בנאי רגיל לא יכול להחזיר שום דבר באמצעות return.

כעת ה-JSON נקרא במקום אחד. שאר האפליקציה מקבלת User אמיתי, שבו user.name הוא String ושגיאת הקלדה גורמת לשגיאת קומפילציה במקום ל-null:

final body = await fetch('/user');
return User.fromJson(jsonDecode(body));

כמעט בכל אפליקציה שמתקשרת עם שרת יש fromJson עבור כל סוג של נתונים שהיא מקבלת.

challenge icon

אתגר

קשה

בפרופיל מופיע Unknown: loadUser מתעלמת מ־JSON. הוסיפו ל־User את factory User.fromJson(Map<String, dynamic> json), שקוראת את name, את email ואת age, וגרמו ל־loadUser להחזיר User.fromJson(jsonDecode(body)). ייבאו את dart:convert.

נסו בעצמכם

import 'package:flutter/material.dart';

import 'api.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: ProfileScreen(),
    );
  }
}

class ProfileScreen extends StatefulWidget {
  const ProfileScreen({super.key});

  @override
  State<ProfileScreen> createState() => _ProfileScreenState();
}

class _ProfileScreenState extends State<ProfileScreen> {
  late Future<User> _user;

  @override
  void initState() {
    super.initState();
    _user = loadUser();
  }

  Future<User> loadUser() async {
    final body = await fetch('/user');
    print(body);
    return User(name: 'Unknown', email: 'unknown', age: 0);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Profile')),
      body: Center(
        child: FutureBuilder<User>(
          future: _user,
          builder: (context, snapshot) {
            if (snapshot.hasError) {
              return Text('Could not load: ${snapshot.error}');
            }
            if (snapshot.hasData) {
              final user = snapshot.data!;
              return Column(
                mainAxisSize: MainAxisSize.min,
                children: [
                  Text(
                    user.name,
                    style: const TextStyle(fontSize: 28, fontWeight: FontWeight.bold),
                  ),
                  const SizedBox(height: 8),
                  Text(user.email, style: const TextStyle(fontSize: 18)),
                  const SizedBox(height: 8),
                  Text('${user.age} years old'),
                ],
              );
            }
            return const CircularProgressIndicator();
          },
        ),
      ),
    );
  }
}

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

  final String name;
  final String email;
  final int age;
}
quiz iconבחנו את עצמכם

השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.

כל השיעורים ביחידה נתונים ורשת

תרגלו בעצמכם: קומפיילר Flutter אונליין