最佳實踐
為了確保程式碼具有良好的可維護性, 這裡列出了您在使用 Riverpod 時應遵循的良好實踐。
此列表並不詳盡,並且可能會發生變化。
如果您有任何建議,請隨時提出問題。
此列表中的專案沒有任何特定的順序。
這些建議的很大一部分可以透過 riverpod_lint 來執行。 請參閱入門指南瞭解安裝說明。
避免!在小部件中初始化提供者程式
提供者程式應自行初始化。
它們不應由外部元素(例如小部件)初始化。
如果不這樣做可能會導致可能的競爭條件和意外行為。
不要
class WidgetState extends State<MyWidget> {
void initState() {
super.initState();
// 壞的:提供者程式應該自己初始化自己
ref.read(provider).init();
}
}
考慮
對於這個問題,沒有“一刀切”的解決方案。
如果您的初始化邏輯取決於提供者程式的外部因素,
則放置此類邏輯的正確位置通常是觸發導航的按鈕的 onPressed
方法中:
ElevatedButton(
onPressed: () {
ref.read(provider).init();
Navigator.of(context).push(...);
},
child: Text('Navigate'),
)
避免!使用本地小部件狀態的提供者程式。
提供者程式被設計為共享業務狀態。 它們不適合用於本地小部件狀態,例如:
- 儲存表單狀態
- 當前選擇的專案
- 動畫
- Flutter 處理常見的 "controller" 相關的所有內容(例如
TextEditingController
)
如果您正在尋找一種處理本地小部件狀態的方法,請考慮使用 flutter_hooks 代替。
不鼓勵這樣做的一個原因是這種狀態通常僅限於一條路由。
如果不這樣做,可能會破壞應用程式的後退按鈕,因為新頁面會覆蓋上一頁的狀態。
不要!在提供者程式初始化期間執行副作用
提供者程式通常應用於表示“讀”操作。 您不應該將它們用於“寫”操作,例如提交表單。
使用提供者程式進行此類操作可能會產生意外行為,例如 如果執行了前一個操作,則跳過副作用。
如果您正在尋找一種處理副作用的載入/錯誤狀態的方法, 請參閱執行副作用。
不要:
final submitProvider = FutureProvider((ref) async {
final formState = ref.watch(formState);
// 壞的:提供者程式不應用於“寫”操作。
return http.post('https://my-api.com', body: formState.toJson());
});
首選!ref.watch/read/listen(和類似的 API)以及靜態已知的提供者程式
Riverpod 強烈建議啟用 lint 規則(透過 riverpod_lint)。
但為了使 lint 發揮作用,您的程式碼應該以可靜態分析的方式編寫。
如果不這樣做,可能會更難發現錯誤或導致 lints 誤報。
應該:
final provider = Provider((ref) => 42);
...
// 好的,因為提供者程式是靜態已知的
ref.watch(provider);
不要:
class Example extends ConsumerWidget {
Example({required this.provider});
final Provider<int> provider;
Widget build(context, ref) {
// 不好,因為靜態分析無法知道 `provider` 是什麼
ref.watch(provider);
}
}
避免!動態建立提供者程式
提供者程式應該專門是頂級 final 變數。
應該:
final provider = Provider<String>((ref) => 'Hello world');
不要:
class Example {
// 不支援的操作。可能導致記憶體洩漏和意外行為。
final provider = Provider<String>((ref) => 'Hello world');
}
資訊
允許將提供者程式建立為 static final 變數, 但程式碼生成器不支援。