hooks-riverpod 使用

简介: hooks-riverpod 使用
1. hook

需要继承HookWidget

useMemoized

useRef useCallback 通过内部使用useMemoized 只调用一次

useEffect

1.1 属性 行为 组合成了状态,除了状态还有作用
1.2 keys

指定是否应重用 [HookState] 或应创建新的对象列表。创建新的 [Hook] 时,框架会使用

[Hook.shouldPreserveState] 检查键是否匹配。如果没有,之前创建的 [HookState] 将被释放,并使用 [Hook.createState] 创建一个新的,然后是 [HookState.initHook]

2. useMemoized

缓存复杂对象的实例。

useMemoized->_MemoizedHook->_MemoizedHookState-> late final T value = hook.valueBuilder()

build 返回的一直都是value, 需要手动调用

一般useFuture useMemoized 配合使用

3. useCallback

缓存函数对象的实例

4. useRef

创建一个包含单个可变属性的对象。改变对象的属性是无效的。这对于在“构建”调用之间共享状态非常有用,而不会导致不必要的重构。

5. useEffect

对于需要取消的

useEffect->_EffectHook->_EffectHookState->initHook()->disposer = hook.effect()->dispose() => disposer?.call()

会在第一次build的时候主动调用,无需手动调用

dispose

6.1 其他钩子

useValueNotifier

useListenable->_ListenableHook->_ListenableStateHook->_listener->setState

useValueListenable->_UseValueListenableHook->_ListenableHook->

useValueListenable比useListenable多加了一个方法,有了返回值

useListenable相当于ValueListenableBuilder->_valueChanged->setState

useListenableSelector 多了一个条件,如果两个值不一样的时候才build

useAnimationController

useAnimation 相当于AnimatedBuilder->_handleChange->setState


useStreamController

useStream 相当于StreamBuilder


useFuture 相当于FutureBuilder


useReducer state一个是对象, action一个是参数

通过dispatch发送参数来返回新的state

6.2 useXXXX 自定义钩子
7. riverpod

runApp(const ProviderScope(child: App()));

需要继承ConsumerWidget 使用WidgetRef ref

继承 StateNotifier ChangeNotifier

ChangeNotifierProvider StateNotifierProvider

ref.watch 观察刷新

ref.read 修改

ref.listen 监听

8. 常用Provider

FutureProvider

StreamProvider.family可以传入参数

FutureProvider.autoDispose

StateNotifierProvider

StateController

Provider

9. 局部刷新

ValueListenableBuilder

ValueNotifier

Listenable

10. Consumer使用 ,局部刷新

提供程序更新时重建尽可能少的小部件

class Example extends StatefulWidget {
  @override
  _ExampleState createState() => _ExampleState();
}
class _ExampleState extends State<Example> {
  @override
  Widget build(BuildContext context) {
    return Consumer(
      builder: (context, ref, child) {
        final value = ref.watch(helloWorldProvider);
        return Text(value); // Hello world
      },
    );
  }
}
11. HookBuilder使用 ,局部刷新
      HookBuilder(builder: (BuildContext context){
                      final num = useState(8);
                      print("HookBuilder-build");
                       return TextButton(
                           onPressed: () {
                             num.value++;
                           },
                           child: Text("num=${num.value}"));
                    })

12 . hook源码分析
Hook
  1. HookWidget vs StatefulWidget
  2. HookElement vs StatefulElement
  3. HookState vs State
abstract class Hook<R> with Diagnosticable {
    final List<Object?>? keys;
    static R use<R>(Hook<R> hook) {
     return HookElement._currentHookElement!._use(hook);
    }
    
     static bool shouldPreserveState(Hook<Object?> hook1, Hook<Object?> hook2) {}
     
     
      @protected
  HookState<R, Hook<R>> createState();
}
1. HookWidget vs StatefulWidget
abstract class HookWidget extends StatelessWidget {
  /// Initializes [key] for subclasses.
  const HookWidget({Key? key}) : super(key: key);

  @override
  _StatelessHookElement createElement() => _StatelessHookElement(this);
}

abstract class StatefulWidget extends Widget {
  const StatefulWidget({ super.key });
  @override
  StatefulElement createElement() => StatefulElement(this);
  
  State createState();
}

2. StatefulElement vs HookElement
///
class StatefulElement extends ComponentElement {
    StatefulElement():_state = createState(){
        _state.element = this;
        _state.widget = widget;
    }
        
     _firstBuild(){
        _state.initState();
        _state.didChangeDependencies();
        rebuild();///performRebuild();
    }
    
     _update(){
        _state.didUpdateWidget();
        rebuild();
    }
    
    build()=>_state.build(this);
    
    performRebuild(){
      state.didChangeDependencies();
    }
    
    activate(){
    _state.activate();
    }
    
    deactivete(){
    _state.deactivate():
    }
    
    unamount(){
     _state.dispose();
    }
}


class _StatelessHookElement extends StatelessElement with HookElement {
  _StatelessHookElement(HookWidget hooks) : super(hooks);
}


HookElement
  1. 一个hookElement中有多个Hook,每个hook对应一个hookstate
  2. 可以根据keys,hookstate不变,但是hook重新赋值 和State对weidget(key,runtype)是一样的
mixin HookElement on ComponentElement {

static HookElement? _currentHookElement;
  _Entry<HookState<Object?, Hook<Object?>>>? _currentHookState;
  
  ///一个HookElement对应多个HookState
  final _hooks = LinkedList<_Entry<HookState<Object?, Hook<Object?>>>>();
  final _shouldRebuildQueue = LinkedList<_Entry<bool Function()>>();
  LinkedList<_Entry<HookState<Object?, Hook<Object?>>>>? _needDispose;
  bool? _isOptionalRebuild = false;
  Widget? _buildCache;



  Widget build() {
  final mustRebuild = _isOptionalRebuild != true ||
        _shouldRebuildQueue.any((cb) => cb.value());

    _isOptionalRebuild = null;
    _shouldRebuildQueue.clear();

    if (!mustRebuild) {
      return _buildCache!;
    }
    _currentHookState = _hooks.isEmpty ? null : _hooks.first;
    HookElement._currentHookElement = this;
   return _buildCache;
  }

 R _use<R>(Hook<R> hook) {
 ///如果为空应为列表中为空 直接添加
   if (_currentHookState == null) {
      _appendHook(hook);
    }else if(hook.runtimeType != _currentHookState!.value.hook.runtimeType){
     /// 是一个新的hook
      _appendHook(hook);
    }else if (hook != _currentHookState!.value.hook) {
        
         final previousHook = _currentHookState!.value.hook;
      if (Hook.shouldPreserveState(previousHook, hook)) {
         ///说明keys不一样了 需要重新hook
        _currentHookState!.value
          .._hook = hook
          ..didUpdateHook(previousHook);
      } else {
      ///新创建一个State
        _needDispose ??= LinkedList();
        _needDispose!.add(_Entry(_currentHookState!.value));
        _currentHookState!.value = _createHookState<R>(hook);
      }
    
    }
     final result = _currentHookState!.value.build(this) as R;
       _currentHookState = _currentHookState!.next;
    return result;
  }
 }

3. HookState vs State
///State
bool get mounted => _element != null;



///HookState
 void markMayNeedRebuild() {
    if (_element!._isOptionalRebuild != false) {
      _element!
        .._isOptionalRebuild = true
        .._shouldRebuildQueue.add(_Entry(shouldRebuild))
        ..markNeedsBuild();
    }
    assert(_element!.dirty, 'Bad state');
  }


13. studyflutter代码

代码

相关文章
Flutter Getx 路由 until 方法帮助你跳转指定路由
不少同学都会问我,这样一个场景,当我点击商品列表,进入商品页,点击购买,支付成功后,想返回商品页,或者我的中心的订单列表。怎么做,这中间跨度了 n 个路由。 我不只一次的推荐 GetX 的 until 方法,和 offNamedUntil 方法。 我写了个 demo 今天我们就一起来看下这两个方法如何使用。
2078 0
Flutter Getx 路由 until 方法帮助你跳转指定路由
|
1月前
|
安全 Linux PHP
Web渗透-命令执行漏洞-及常见靶场检测实战
命令执行漏洞(RCE)指应用程序调用系统命令时,用户可控制输入参数,导致恶意命令被拼接执行,从而危害系统安全。常见于PHP的system、exec等函数。攻击者可通过命令连接符在目标系统上执行任意命令,造成数据泄露或服务瘫痪。漏洞成因包括代码层过滤不严、第三方组件缺陷等。可通过参数过滤、最小权限运行等方式防御。本文还介绍了绕过方式、靶场测试及复现过程。
305 0
|
11月前
|
C# Android开发 虚拟化
C# 一分钟浅谈:MAUI 跨平台移动应用开发
.NET MAUI 是 Microsoft 推出的跨平台框架,支持 Windows、macOS、iOS 和 Android。本文从基础概念入手,探讨 MAUI 的常见问题、易错点及解决方案,并通过代码示例详细说明。涵盖平台特定代码、XAML 语法、数据绑定、性能优化和调试技巧等内容,帮助开发者更好地掌握 .NET MAUI。
1006 55
|
12月前
|
运维 监控 jenkins
Jenkins有哪些优势和劣势
【10月更文挑战第18天】Jenkins有哪些优势和劣势
453 2
|
12月前
|
监控 安全 网络安全
如何防止内网渗透攻击?
【10月更文挑战第10天】如何防止内网渗透攻击?
720 3
|
7月前
|
开发工具 git
vscode推送项目到github仓库故障解决1
本文介绍了如何优雅解决本地仓库与远程仓库历史记录不一致的问题,并提供避免未来问题的最佳实践。核心在于理解问题根源(如历史记录差异和常见原因),采用推荐的解决方案(先本地初始化再关联远程仓库),并遵循一致的工作流程、团队协作规范及熟悉 Git 命令。通过强制推送或合并无关历史记录等方式处理现有冲突,同时养成良好习惯以预防类似问题。
|
人工智能 自然语言处理 API
云栖发布:通义听悟AI能力再进化,开放API接口
云栖发布:通义听悟AI能力再进化,开放API接口
|
11月前
|
开发工具 开发者
Flutter&鸿蒙next 状态管理高级使用:深入探讨 Provider
本文深入探讨了 Flutter 中 Provider 的高级用法,涵盖多 Provider 组合、Selector 优化性能、ChangeNotifierProxyProvider 管理依赖关系以及自定义 Provider。通过这些技巧,开发者可以构建高效、可维护的响应式应用。
390 2
|
11月前
|
机器学习/深度学习 人工智能 监控
探索 AI 在软件开发中的新角色:代码审查与质量保证
【10月更文挑战第22天】本文探讨了AI在软件开发中的新角色,特别是在代码审查和质量保证方面。AI通过静态代码分析、代码风格一致性检查和历史数据学习,提高代码审查的效率和准确性。在质量保证中,AI还能够自动生成测试用例、监控应用性能并持续优化。文章还讨论了AI在软件开发中的实践应用、挑战与机遇,以及实施的最佳实践。
flutter:定时器&通过key操作状态 (十二)
本文档介绍了Flutter中的定时器使用方法、通过key操作状态的几种方式,包括localKey和GlobalKey的使用场景与示例代码,以及如何处理屏幕旋转导致的组件状态丢失问题。通过配置全局key,可以有效地管理父子组件之间的状态交互,确保在屏幕旋转等情况下保持组件状态的一致性。
135 0