Halo semuanya! Pada artikel ini, saya ingin menunjukkan kepada Anda cara membuat aplikasi Flutter menggunakan Redux. Jika Anda tidak tahu apa itu
Flutter , maka ini adalah SDK open source untuk membuat aplikasi seluler dari Google. Ini digunakan untuk mengembangkan aplikasi untuk Android dan iOS, dan itu juga satu-satunya cara untuk mengembangkan aplikasi untuk Google Fuchsia.
Jika Anda terbiasa dengan Flutter dan ingin membuat aplikasi yang dirancang dengan baik, mudah diuji, dan memiliki perilaku yang sangat mudah ditebak, lanjutkan membaca artikel ini dan Anda akan segera mengetahuinya!
Tetapi sebelum kita mulai menulis aplikasi itu sendiri. Mari kita sedikit berkenalan dengan teori, mari kita mulai dengan menjelaskan apa itu Redux.
Apa itu Redux?
Redux adalah arsitektur yang awalnya dibuat untuk bahasa JavaScript dan digunakan dalam aplikasi yang dibuat menggunakan
kerangka kerja reaktif (seperti React Native atau Flutter). Redux adalah versi sederhana dari arsitektur Flux yang dibuat oleh Facebook. Intinya, Anda perlu tahu tiga hal:
- Satu-satunya sumber kebenaran - seluruh keadaan aplikasi Anda disimpan hanya di satu tempat (disebut store ).
- state read-only / state read-only - untuk mengubah status aplikasi, Anda perlu mengirim tindakan (action), setelah itu negara baru akan dibuat
- perubahan dibuat menggunakan fungsi murni / fungsi murni - fungsi murni (untuk kesederhanaan, itu adalah fungsi tanpa efek samping) mengambil aplikasi keadaan saat ini dan tindakan dan mengembalikan keadaan aplikasi yang baru
Catatan: Efek samping dari fungsi adalah kemampuan, dalam proses melakukan perhitungannya: untuk membaca dan memodifikasi nilai-nilai variabel global, melaksanakan operasi I / O, merespons situasi luar biasa, dan memanggil penangannya. Jika Anda memanggil fungsi dengan efek samping dua kali dengan set nilai argumen input yang sama, mungkin terjadi bahwa nilai yang berbeda dikembalikan sebagai hasilnya. Fungsi tersebut disebut fungsi non-deterministik dengan efek samping.Kedengarannya keren, tetapi apa manfaat dari solusi ini?
- kami memiliki kontrol atas negara / negara bagian - ini berarti bahwa kami tahu persis apa yang menyebabkan perubahan keadaan, kami tidak memiliki status rangkap, dan kami dapat dengan mudah memantau aliran data
- Peredam adalah fungsi murni yang mudah diuji - kita dapat melewati status, bertindak ke input dan memeriksa apakah hasilnya benar
- Aplikasi terstruktur dengan jelas - kami memiliki lapisan yang berbeda untuk tindakan, model, logika bisnis, dll. - sehingga Anda tahu persis di mana menambahkan fitur baru lainnya
- ini adalah arsitektur yang hebat untuk aplikasi yang lebih kompleks - Anda tidak perlu memberikan status melintasi seluruh pohon pandangan Anda dari orangtua ke anak
- dan ada satu lagi ...
Perjalanan waktu redux
Redux memiliki satu peluang menarik - Perjalanan Waktu! Dengan Redux dan alat terkait, Anda dapat melacak keadaan aplikasi Anda dari waktu ke waktu, memeriksa keadaan sebenarnya dan membuatnya kembali kapan saja. Lihat fitur ini dalam aksi:
Widget Redux dengan Contoh Sederhana
Semua aturan di atas membuat aliran data di Redux searah. Tapi apa artinya itu? Dalam praktiknya, semua ini dilakukan dengan menggunakan
tindakan ,
reduksi ,
penyimpanan , dan
status . Mari kita bayangkan aplikasi yang menampilkan penghitung:
- Aplikasi Anda memiliki status tertentu saat startup (jumlah klik, yaitu 0)
- Berdasarkan kondisi ini, tampilan diberikan.
- Jika pengguna mengklik tombol, tindakan dikirim (misalnya, IncrementCounter)
- Setelah itu, tindakan menerima peredam yang mengetahui keadaan sebelumnya (penghitung 0), dan menerima tindakan (IncrementCounter) dan dapat mengembalikan keadaan baru (penghitung sekarang 1)
- Aplikasi kami memiliki status baru (penghitung adalah 1)
- Berdasarkan status baru, tampilan digambar ulang, yang menampilkan status saat ini
Jadi, seperti yang Anda lihat, biasanya ini semua tentang
keadaan . Anda memiliki satu status dari keseluruhan aplikasi,
status hanya-baca , dan untuk membuat status baru Anda perlu mengirim
tindakan .
Tindakan pengajuan meluncurkan
peredam , yang menciptakan dan mengembalikan kepada kami
keadaan baru. Dan ceritanya berulang.
Mari kita membuat aplikasi kecil dan mengenal implementasi pendekatan Redux dalam aksi, aplikasi akan disebut "
Daftar Belanja "
Kita akan melihat bagaimana Redux bekerja dalam praktiknya. Kami akan membuat aplikasi ShoppingCart sederhana. Aplikasi akan memiliki fitur-fitur seperti:
- menambahkan pembelian
- Anda dapat menandai pembelian sebagai selesai
- dan itu pada dasarnya semua
Aplikasi akan terlihat seperti ini:
Mari kita mulai menulis kode!
Prasyarat
Pada artikel ini, saya tidak akan menunjukkan pembuatan antarmuka pengguna untuk aplikasi ini.
Anda dapat membiasakan diri dengan kode yang saya siapkan untuk Anda sebelum melanjutkan dengan penyelaman Redux . Setelah itu kami akan terus menulis kode dan menambahkan
Redux ke aplikasi saat ini.
Catatan: Jika Anda belum pernah menggunakan Flutter sebelumnya, saya sarankan Anda mencoba Flutter Codelabs dari Google .Persiapan awal
Untuk mulai menggunakan
Redux untuk Flutter, kita perlu menambahkan dependensi ke file
pubspec.yaml :
flutter_redux: ^0.5.2
Anda juga dapat memeriksa versi dependensi ini dengan membuka halaman
flutter_redux .
Pada saat penulisan, versinya adalah, flutter_redux 0.6.0Model
Aplikasi kita harus bisa mengendalikan penambahan dan modifikasi elemen, jadi kita akan menggunakan model
CartItem sederhana untuk menyimpan status satu elemen. Semua status aplikasi kita hanya akan menjadi daftar CartItems. Seperti yang Anda lihat, CartItem hanyalah sebuah objek.
class CartItem { String name; bool checked; CartItem(this.name, this.checked); }
Pertama, kita perlu menyatakan tindakan. Sebenarnya, tindakan adalah segala niat yang dapat digunakan untuk mengubah status aplikasi. Intinya, akan ada dua tindakan untuk menambah dan mengubah elemen:
class AddItemAction { final CartItem item; AddItemAction(this.item); } class ToggleItemStateAction { final CartItem item; ToggleItemStateAction(this.item); }
Maka kita perlu memberi tahu aplikasi kita apa yang harus dilakukan dengan
tindakan ini. Itu sebabnya
reduksi digunakan - mereka hanya mengambil status aplikasi saat ini dan tindakan (status aplikasi dan tindakan), lalu membuat dan mengembalikan status baru. Kami akan memiliki dua metode
peredam :
List<CartItem> appReducers(List<CartItem> items, dynamic action) { if (action is AddItemAction) { return addItem(items, action); } else if (action is ToggleItemStateAction) { return toggleItemState(items, action); } return items; } List<CartItem> addItem(List<CartItem> items, AddItemAction action) { return List.from(items)..add(action.item); } List<CartItem> toggleItemState(List<CartItem> items, ToggleItemStateAction action) { return items.map((item) => item.name == action.item.name ? action.item : item).toList(); }
Metode
appReducers () mendelegasikan tindakan ke metode yang sesuai. Kedua
metode addItem () dan
toggleItemState () mengembalikan daftar baru - ini adalah keadaan / keadaan baru kita. Seperti yang Anda lihat, Anda
tidak boleh mengubah daftar saat ini . Sebagai gantinya, kami membuat daftar baru setiap kali.
StoreProvider
Sekarang kita memiliki
tindakan dan
reduksi , kita perlu menyediakan tempat untuk menyimpan
status aplikasi . Di Redux, ini disebut
toko dan satu-satunya sumber kebenaran untuk aplikasi tersebut.
void main() { final store = new Store<List<CartItem>>( appReducers, initialState: new List()); runApp(new FlutterReduxApp(store)); }
Untuk membuat
toko , kita harus melewati metode
reduksi dan status awal. Jika kami membuat
toko , kami harus meneruskannya ke
StoreProvider untuk memberi tahu aplikasi kami bahwa
toko itu dapat digunakan oleh siapa saja yang ingin meminta
status aplikasi saat ini.
class FlutterReduxApp extends StatelessWidget { final Store<List<CartItem>> store; FlutterReduxApp(this.store); @override Widget build(BuildContext context) { return new StoreProvider<List<CartItem>>( store: store, child: new ShoppingCartApp(), ); } }
Dalam contoh di atas,
ShoppingCartApp ( ) adalah widget utama aplikasi kita.
StoreConnector
Saat ini kami memiliki semuanya kecuali ... benar-benar menambahkan dan mengubah item untuk dibeli. Bagaimana cara melakukannya? Untuk memungkinkan ini, kita perlu menggunakan
StoreConnector . Ini adalah cara untuk mendapatkan
toko dan mengirimkannya beberapa
tindakan atau hanya mendapatkan kondisi saat ini.
Pertama, kami ingin mendapatkan data saat ini dan menampilkannya sebagai daftar di layar:
class ShoppingList extends StatelessWidget { @override Widget build(BuildContext context) { return new StoreConnector<List<CartItem>, List<CartItem>>( converter: (store) => store.state, builder: (context, list) { return new ListView.builder( itemCount: list.length, itemBuilder: (context, position) => new ShoppingListItem(list[position])); }, ); } }
Kode di atas membungkus
ListView.builder dengan
StoreConnector .
StoreConnector dapat menerima
keadaan saat ini (yang merupakan daftar item
) dan dengan bantuan fungsi peta kita dapat mengubahnya menjadi apa pun. Tetapi dalam kasus kami itu akan menjadi negara yang sama (Daftar), karena di sini kita membutuhkan daftar belanja.
Selanjutnya, dalam fungsi builder , kita mendapatkan daftar - yang pada dasarnya adalah daftar CartItems dari toko , yang dapat kita gunakan untuk membuat ListView .
Oke, keren - kami punya data. Sekarang, bagaimana cara mengatur beberapa data?
Untuk ini, kami juga akan menggunakan StoreConnector , tetapi dengan cara yang sedikit berbeda.
class AddItemDialog extends StatelessWidget { @override Widget build(BuildContext context) { return new StoreConnector<List<CartItem>, OnItemAddedCallback>( converter: (store) { return (itemName) => store.dispatch(AddItemAction(CartItem(itemName, false))); }, builder: (context, callback) { return new AddItemDialogWidget(callback); }); } }typedef OnItemAddedCallback = Function(String itemName);
Mari kita lihat kodenya. Kami menggunakan StoreConnector , seperti pada contoh sebelumnya, tetapi kali ini, alih-alih mencocokkan daftar CartItems dengan daftar yang sama, kami akan melakukan konversi menggunakan peta ke OnItemAddedCallback . Dengan demikian, kita dapat meneruskan fungsi panggilan balik ke AddItemDialogWidget dan menyebutnya ketika pengguna menambahkan elemen baru:
class AddItemDialogWidgetState extends State<AddItemDialogWidget> { String itemName; final OnItemAddedCallback callback; AddItemDialogWidgetState(this.callback); @override Widget build(BuildContext context) { return new AlertDialog( ... actions: <Widget>[ ... new FlatButton( child: const Text('ADD'), onPressed: () { ... callback(itemName); }) ], ); } }
Sekarang setiap kali pengguna mengklik tombol ADD, fungsi callback mengirimkan tindakan AddItemAction () .
Sekarang kita dapat membuat implementasi yang sangat mirip untuk mengubah keadaan elemen.
class ShoppingListItem extends StatelessWidget { final CartItem item; ShoppingListItem(this.item); @override Widget build(BuildContext context) { return new StoreConnector<List<CartItem>, OnStateChanged>( converter: (store) { return (item) => store.dispatch(ToggleItemStateAction(item)); }, builder: (context, callback) { return new ListTile( title: new Text(item.name), leading: new Checkbox( value: item.checked, onChanged: (bool newValue) { callback(CartItem(item.name, newValue)); }), ); }); } }
Seperti pada contoh sebelumnya, kami menggunakan StoreConnector untuk menampilkan Daftar untuk fungsi panggilan balik OnStateChanged . Sekarang setiap kali flag berubah (dalam metode onChanged), fungsi callback memecat event ToggleItemStateAction .
Ringkasan
Itu saja! Pada artikel ini, kami membuat aplikasi sederhana yang menampilkan daftar belanja dan sedikit terbenam dalam menggunakan arsitektur Redux. Dalam aplikasi kita, kita dapat menambahkan elemen dan mengubah kondisinya. Menambahkan fitur baru ke aplikasi ini semudah menambahkan tindakan dan reduksi baru .
Di sini Anda dapat menemukan kode sumber aplikasi ini, termasuk widget Time Travel :
Semoga Anda menikmati posting ini!