Upgrade to Pro — share decks privately, control downloads, hide ads and more …

riverpodを理解したい

tatsubee
October 26, 2023

 riverpodを理解したい

tatsubee

October 26, 2023
Tweet

More Decks by tatsubee

Other Decks in Technology

Transcript

  1. riverpodを理解したい
    pixiv Inc.
    tatsubee
    2023.10.26

    View full-size slide

  2. 2
    自己紹介
    ● 23新卒
    ● 福岡生まれ
    福岡育ち
    東京在住
    ● 最近やっていること
    ○ お絵描き
    ○ テニス
    ○ iOS
    tatsubee
    iOSエンジニア

    View full-size slide

  3. 3
    初めにちょっとだけ宣伝

    View full-size slide

  4. 5
    福岡のFlutterコミュニティ
    様々なイベントを開催して活発に活動中!
    ● 月一でのLTイベント開催
    ● 先日の東京Flutterハッカソンへの参加
    ● その他内輪の勉強会
    などなど

    View full-size slide

  5. 6
    福岡のFlutterコミュニティ
    様々なイベントを開催して活発に活動中!!!
    ● 月一でのLTイベント開催
    ● 東京Flutterハッカソンへの参加
    ● その他内輪の勉強会
    などなど

    View full-size slide

  6. 8
    riverpod勉強会
    Fukuoka Flutter Fanclubで毎週やっている勉強会
    目標: riverpodを「作れる」レベルのコード理解
    ↓を順に、1時間でできる範囲でドキュメントやコードを読み進めていく
    ● riverpodでできることの把握
    ● InheritedWidgetのコード理解
    ● providerのコード理解
    ● riverpodのコード理解

    View full-size slide

  7. 9
    riverpod勉強会
    Fukuoka Flutter Fanclubで毎週やっている勉強会
    目標: riverpodを「作れる」レベルのコード理解
    ↓を順に、1時間でできる範囲でドキュメントやコードを読み進めていく
    ● riverpodでできることの把握
    ● InheritedWidgetのコード理解 ←ここまで進んだ
    ● providerのコード理解
    ● riverpodのコード理解

    View full-size slide

  8. 10
    このLTの内容
    riverpod

    View full-size slide

  9. 11
    このLTの内容
    riverpod
    InheritedWidget

    View full-size slide

  10. 12
    InheritedWidget
    特徴
    ● 祖先のWidgetが管理する値にO(1)でアクセスできる
    ● 値を購読する子孫のWidgetに、その値の変更を通知することができる
    (riverpodやproviderがあるので直接扱う必要性はない)

    View full-size slide

  11. class Parent extends StatefulWidget { … }
    class _ParentState extends State {
    int count = 0;
    @override
    Widget build(BuildContext context) {
    return CountInherited(
    count: count,
    child: Scaffold(
    body: const Center(
    child: Child(),
    ),
    floatingActionButton: FloatingActionButton(
    onPressed: () => setState(() {
    count++;
    }),
    ),
    ),
    );
    }
    }
    13
    InheritedWidget

    View full-size slide

  12. class Parent extends StatefulWidget { … }
    class _ParentState extends State {
    int count = 0;
    @override
    Widget build(BuildContext context) {
    return CountInherited(
    count: count,
    child: Scaffold(
    body: const Center(
    child: Child(),
    ),
    floatingActionButton: FloatingActionButton(
    onPressed: () => setState(() {
    count++;
    }),
    ),
    ),
    );
    }
    }
    14
    InheritedWidget
    class Child extends StatelessWidget {
    const Child({super.key});
    @override
    Widget build(BuildContext context) =>
    Text('${CountInherited.of(context).count}');
    }

    View full-size slide

  13. class Parent extends StatefulWidget { … }
    class _ParentState extends State {
    int count = 0;
    @override
    Widget build(BuildContext context) {
    return CountInherited(
    count: count,
    child: Scaffold(
    body: const Center(
    child: Child(),
    ),
    floatingActionButton: FloatingActionButton(
    onPressed: () => setState(() {
    count++;
    }),
    ),
    ),
    );
    }
    }
    15
    InheritedWidget
    class CountInherited extends InheritedWidget {
    const CountInherited({
    super.key,
    required this.count,
    required super.child,
    });
    final int count;
    static CountInherited of(BuildContext context) =>
    context.dependOnInheritedWidgetOfExactType()!;
    @override
    bool updateShouldNotify(CountInherited oldWidget) =>
    oldWidget.count != count;
    }

    View full-size slide

  14. class Parent extends StatefulWidget { … }
    class _ParentState extends State {
    int count = 0;
    @override
    Widget build(BuildContext context) {
    return CountInherited(
    count: count,
    child: Scaffold(
    body: const Center(
    child: Child(),
    ),
    floatingActionButton: FloatingActionButton(
    onPressed: () => setState(() {
    count++;
    }),
    ),
    ),
    );
    }
    }
    16
    InheritedWidget

    View full-size slide

  15. class Parent extends StatefulWidget { … }
    class _ParentState extends State {
    int count = 0;
    @override
    Widget build(BuildContext context) {
    return CountInherited(
    count: count,
    child: Scaffold(
    body: const Center(
    child: Child(),
    ),
    floatingActionButton: FloatingActionButton(
    onPressed: () => setState(() {
    count++;
    }),
    ),
    ),
    );
    }
    }
    17
    InheritedWidget

    View full-size slide

  16. class Parent extends StatefulWidget { … }
    class _ParentState extends State {
    int count = 0;
    @override
    Widget build(BuildContext context) {
    return CountInherited(
    count: count,
    child: Scaffold(
    body: const Center(
    child: Child(),
    ),
    floatingActionButton: FloatingActionButton(
    onPressed: () => setState(() {
    count++;
    }),
    ),
    ),
    );
    }
    }
    18
    InheritedWidget

    View full-size slide

  17. class Parent extends StatefulWidget { … }
    class _ParentState extends State {
    int count = 0;
    @override
    Widget build(BuildContext context) {
    return CountInherited(
    count: count,
    child: Scaffold(
    body: const Center(
    child: Child(),
    ),
    floatingActionButton: FloatingActionButton(
    onPressed: () => setState(() {
    count++;
    }),
    ),
    ),
    );
    }
    }
    19
    InheritedWidget

    View full-size slide

  18. 20
    InheritedWidgetの
    中身を覗いてみる

    View full-size slide

  19. abstract class InheritedWidget extends ProxyWidget {
    const InheritedWidget({ super.key, required super.child });
    @override
    InheritedElement createElement() => InheritedElement(this);
    @protected
    bool updateShouldNotify(covariant InheritedWidget oldWidget);
    }
    21
    InheritedElementの作成と
    変更の通知の判定のみ!

    View full-size slide

  20. class InheritedElement extends ProxyElement {
    InheritedElement(InheritedWidget super.widget);
    final Map _dependents = HashMap();
    @override void _updateInheritance() {...}
    @override void debugDeactivated() {...}
    @protected Object? getDependencies(Element dependent) {...}
    @protected void updateDependencies(Element dependent, Object? aspect) {...}
    @protected
    void notifyDependent(covariant InheritedWidget oldWidget, Element dependent) {...}
    @override void updated(InheritedWidget oldWidget) {...}
    @override void notifyClients(InheritedWidget oldWidget) {...}
    }
    22

    View full-size slide

  21. 23
    O(1)でアクセスする仕組み

    View full-size slide

  22. 24
    アクセス方法

    View full-size slide

  23. abstract class Element extends DiagnosticableTree implements BuildContext {
    PersistentHashMap? _inheritedElements;
    @override
    T? dependOnInheritedWidgetOfExactType({
    Object? aspect
    }) {
    final InheritedElement? ancestor = _inheritedElements == null
    ? null
    : _inheritedElements![T];
    if (ancestor != null) {
    return dependOnInheritedElement(ancestor, aspect: aspect) as T;
    }
    _hadUnsatisfiedDependencies = true;
    return null;
    }
    }
    25
    = watch

    View full-size slide

  24. abstract class Element extends DiagnosticableTree implements BuildContext {
    PersistentHashMap? _inheritedElements;
    @override
    T? dependOnInheritedWidgetOfExactType({
    Object? aspect
    }) {
    final InheritedElement? ancestor = _inheritedElements == null
    ? null
    : _inheritedElements![T];
    if (ancestor != null) {
    return dependOnInheritedElement(ancestor, aspect: aspect) as T;
    }
    _hadUnsatisfiedDependencies = true;
    return null;
    }
    }
    26
    自身が持っている_inheritedElements
    の中から
    型が一致するInheritedElementを返す
    = watch

    View full-size slide

  25. 27
    _inheritedElementsへの格納

    View full-size slide

  26. abstract class Element extends DiagnosticableTree implements BuildContext {
    @mustCallSuper
    void mount(Element? parent, Object? newSlot) {
    _updateInheritance();
    }
    }
    28

    View full-size slide

  27. abstract class Element extends DiagnosticableTree implements BuildContext {
    void _updateInheritance() {
    _inheritedElements = _parent?._inheritedElements;
    }
    }
    class InheritedElement extends ProxyElement {
    @override
    void _updateInheritance() {
    final PersistentHashMap incomingWidgets =
    _parent?._inheritedElements
    ?? const PersistentHashMap.empty();
    _inheritedElements = incomingWidgets.put(widget.runtimeType, this);
    }
    }
    29

    View full-size slide

  28. abstract class Element extends DiagnosticableTree implements BuildContext {
    void _updateInheritance() {
    _inheritedElements = _parent?._inheritedElements;
    }
    }
    class InheritedElement extends ProxyElement {
    @override
    void _updateInheritance() {
    final PersistentHashMap incomingWidgets =
    _parent?._inheritedElements
    ?? const PersistentHashMap.empty();
    _inheritedElements = incomingWidgets.put(widget.runtimeType, this);
    }
    }
    30
    親の_inheritedElenentsを
    そのまま引き継ぐ

    View full-size slide

  29. abstract class Element extends DiagnosticableTree implements BuildContext {
    void _updateInheritance() {
    _inheritedElements = _parent?._inheritedElements;
    }
    }
    class InheritedElement extends ProxyElement {
    @override
    void _updateInheritance() {
    final PersistentHashMap incomingWidgets =
    _parent?._inheritedElements
    ?? const PersistentHashMap.empty();
    _inheritedElements = incomingWidgets.put(widget.runtimeType, this);
    }
    }
    31
    親から引き継いだ
    _inheritedElenentsに
    自身を挿入する

    View full-size slide

  30. 32
    視覚的に見てみると...

    View full-size slide

  31. 33
    Parent
    CounterInherited
    Child
    Widgetツリー
    { }
    { CounterInherited: InheritedElement }
    _inheritedElements
    { CounterInherited: InheritedElement }

    View full-size slide

  32. 34
    Parent
    CounterInherited
    Child
    Widgetツリー
    { }
    { CounterInherited: InheritedElement }
    _inheritedElements
    { CounterInherited: InheritedElement }
    アクセス

    View full-size slide

  33. 35
    変更を通知する仕組み

    View full-size slide

  34. 36
    countの値を変更する時

    View full-size slide

  35. class Parent extends StatefulWidget { … }
    class _ParentState extends State {
    int count = 0;
    @override
    Widget build(BuildContext context) {
    return CountInherited(
    count: count,
    child: Scaffold(
    body: const Center(
    child: Child(),
    ),
    floatingActionButton: FloatingActionButton(
    onPressed: () => setState(() {
    count++;
    }),
    ),
    ),
    );
    }
    }
    37

    View full-size slide

  36. class Parent extends StatefulWidget { … }
    class _ParentState extends State {
    int count = 0;
    @override
    Widget build(BuildContext context) {
    return CountInherited(
    count: count,
    child: Scaffold(
    body: const Center(
    child: Child(),
    ),
    floatingActionButton: FloatingActionButton(
    onPressed: () => setState(() {
    count++;
    }),
    ),
    ),
    );
    }
    }
    38
    リビルド範囲

    View full-size slide

  37. class Parent extends StatefulWidget { … }
    class _ParentState extends State {
    int count = 0;
    @override
    Widget build(BuildContext context) {
    return CountInherited(
    count: count,
    child: Scaffold(
    body: const Center(
    child: Child(),
    ),
    floatingActionButton: FloatingActionButton(
    onPressed: () => setState(() {
    count++;
    }),
    ),
    ),
    );
    }
    }
    39
    リビルド範囲

    View full-size slide

  38. class Parent extends StatefulWidget { … }
    class _ParentState extends State {
    int count = 0;
    @override
    Widget build(BuildContext context) {
    return CountInherited(
    count: count,
    child: Scaffold(
    body: const Center(
    child: Child(),
    ),
    floatingActionButton: FloatingActionButton(
    onPressed: () => setState(() {
    count++;
    }),
    ),
    ),
    );
    }
    }
    40
    リビルド範囲
    リビルドされない constによってリビルドが抑
    制される

    View full-size slide

  39. class Child extends StatelessWidget {
    const Child({super.key});
    @override
    Widget build(BuildContext context) =>
    Text('${CountInherited.of(context).count}');
    }
    41

    View full-size slide

  40. class Child extends StatelessWidget {
    const Child({super.key});
    @override
    Widget build(BuildContext context) =>
    Text('${CountInherited.of(context).count}');
    }
    42
    StatefulWidgetの方が
    わかりやすいので変換

    View full-size slide

  41. class Child extends StatefulWidget { … }
    class _ChildState extends State {
    @override
    void didChangeDependencies() { … }
    @override
    Widget build(BuildContext context) {
    final countInherited =
    context.dependOnInheritedWidgetOfExactType()! as CountInherited;
    return Text('${countInherited.count});
    }
    }
    43
    StatefulWidgetの方が
    わかりやすいので変換

    View full-size slide

  42. class Child extends StatefulWidget { … }
    class _ChildState extends State {
    @override
    void didChangeDependencies() { … }
    @override
    Widget build(BuildContext context) {
    final countInherited =
    context.dependOnInheritedWidgetOfExactType()! as CountInherited;
    return Text('${countInherited.count});
    }
    }
    44
    setStateされると
    didChangeDependencies
    が発火!

    View full-size slide

  43. class Child extends StatefulWidget { … }
    class _ChildState extends State {
    @override
    void didChangeDependencies() { … }
    @override
    Widget build(BuildContext context) {
    final countInherited =
    context.dependOnInheritedWidgetOfExactType()! as CountInherited;
    return Text('${countInherited.count});
    }
    }
    45
    ”Dependencies”とは、
    InheritedWidgetのこと!

    View full-size slide

  44. 46
    時間がなさそうなのでここまで!
    気になる方は懇親会で!

    View full-size slide

  45. class InheritedElement extends ProxyElement {
    InheritedElement(InheritedWidget super.widget);
    final Map _dependents = HashMap();
    @override void _updateInheritance() {...}
    @override void debugDeactivated() {...}
    @protected Object? getDependencies(Element dependent) {...}
    @protected void updateDependencies(Element dependent, Object? aspect) {...}
    @protected
    void notifyDependent(covariant InheritedWidget oldWidget, Element dependent) {...}
    @override void updated(InheritedWidget oldWidget) {...}
    @override void notifyClients(InheritedWidget oldWidget) {...}
    }
    47

    View full-size slide

  46. class InheritedElement extends ProxyElement {
    InheritedElement(InheritedWidget super.widget);
    final Map _dependents = HashMap();
    @override void _updateInheritance() {...}
    @override void debugDeactivated() {...}
    @protected Object? getDependencies(Element dependent) {...}
    @protected void updateDependencies(Element dependent, Object? aspect) {...}
    @protected
    void notifyDependent(covariant InheritedWidget oldWidget, Element dependent) {...}
    @override void updated(InheritedWidget oldWidget) {...}
    @override void notifyClients(InheritedWidget oldWidget) {...}
    }
    48
    Log
    setState
    ParentWidget.build
    InheritedElement.updated
    InheritedWidget.updateShouldNotify:true
    InheritedWidget.updateShouldNotify:true
    InheritedElement.notifyClients
    InheritedElement.notifyDependent
    ChildWidget.didChangeDependencies
    ChildWidget.build
    InheritedElement.updateDependencies
    InheritedElement.setDependencies

    View full-size slide

  47. 49
    ありがとうございました!

    View full-size slide

  48. 50
    魂だけでも福岡に送ってみませんか?
    Discordサーバー

    View full-size slide