flutter-in-action icon indicating copy to clipboard operation
flutter-in-action copied to clipboard

对 「3.2.2 父Widget管理子Widget的状态 」的个人建议

Open JoeyZeng666 opened this issue 6 years ago • 3 comments

您好,首先感谢写出这么好的文章。下面是我的一点小建议: 「3.2.2 父Widget管理子Widget的状态 」中,阐述得很好,但是在代码示例中却用

final ValueChanged onChanged; void _handleTap() { onChanged(!active); }

来做一个回调,这样代码看起来还是又「子widget」来定义了状态。相当于「子Widget」自己通过回调告诉了「父Widget」,“我的状态将会改变为 true”,然后「父Widget」只是调用一个 setState而已。我在阅读这一段的时候感觉有点别扭。 我的理解是「子Widget」只应该知道自己被 tap 了一下,然后「父Widget」来做状态的逻辑处理。代码为:

class TapBoxB extends StatelessWidget{

final bool active ; final GestureTapCallback onTapped;

TapBoxB({Key key,this.active,@required this.onTapped}):super(key:key);

@override Widget build(BuildContext context) {

return GestureDetector( onTap: onTapped, child:// 省略 ); } }

可以举一个场景来阐述,我需要「连点3下TapBoxB」才能把 「TapBoxB」激活,激活后只需tap一次就可以取消激活。讲道理如果是「父Widget」来控制状态的话,TapBoxB应该是不需要改动的。只需要改动 「父Widget」就OK了:

class _TapBoxBWidgetState extends State<TapBoxBParent>{

bool _active = false; int tapCount = 0;

void _handleTap(){ if(_active) { setState(() { _active = false; }); tapCount = 0; return; } if(++tapCount>=3) { setState(() { _active = true; }); } } @override Widget build(BuildContext context) { return new TapBoxB(active: _active,onTapped: _handleTap); } }

当然你之前的写法也可以实现,但是代码看起来很奇怪,「子Widget」不管理自己的状态,那怎么会知道自己 onChanged(active)了呢? 我理解不对的地方,请多多指教。

JoeyZeng666 avatar Dec 23 '19 16:12 JoeyZeng666

这个例子中谁来管理状态就是指谁来保存active的状态,子组件的active属性只是作为了接收父组件传值的参数,内部并没有来维护active的变动情况,子组件点击时新的状态就自然是!active,由于是父组件管理的active状态,所以父组件有权决定要不要用最新的状态来重新构建子组件(调用setState), 如果父组件不需要重新构建子组件,那么即使子组件点多少次,状态都不会变。

wendux avatar Dec 25 '19 08:12 wendux

感谢。

JoeyZeng666 avatar Jan 29 '20 14:01 JoeyZeng666

@wendux 你好 刚好看到这一节,使用这一节的源码,运行报错,不知道是什么原因 I/flutter ( 2285): ══╡ EXCEPTION CAUGHT BY GESTURE ╞═══════════════════════════════════════════════════════════════════ I/flutter ( 2285): The following NoSuchMethodError was thrown while handling a gesture: I/flutter ( 2285): The method 'call' was called on null. I/flutter ( 2285): Receiver: null I/flutter ( 2285): Tried calling: call(true) I/flutter ( 2285): When the exception was thrown, this was the stack: I/flutter ( 2285): #0 Object.noSuchMethod (dart:core-patch/object_patch.dart:53:5) I/flutter ( 2285): #1 TapboxB._handleTap (package:first_flutter_app/TapboxB.dart:41:5) I/flutter ( 2285): #2 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:182:24) I/flutter ( 2285): #3 TapGestureRecognizer.handleTapUp (package:flutter/src/gestures/tap.dart:486:11) I/flutter ( 2285): #4 BaseTapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:264:5) I/flutter ( 2285): #5 BaseTapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:199:7) I/flutter ( 2285): #6 PrimaryPointerGestureRecognizer.handleEvent (package:flutter/src/gestures/recognizer.dart:470:9) I/flutter ( 2285): #7 PointerRouter._dispatch (package:flutter/src/gestures/pointer_router.dart:76:12) I/flutter ( 2285): #8 PointerRouter._dispatchEventToRoutes. (package:flutter/src/gestures/pointer_router.dart:117:9) I/flutter ( 2285): #9 _LinkedHashMapMixin.forEach (dart:collection-patch/compact_hash.dart:379:8) I/flutter ( 2285): #10 PointerRouter._dispatchEventToRoutes (package:flutter/src/gestures/pointer_router.dart:115:18) I/flutter ( 2285): #11 PointerRouter.route (package:flutter/src/gestures/pointer_router.dart:101:7) I/flutter ( 2285): #12 GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:218:19) I/flutter ( 2285): #13 GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:198:22) I/flutter ( 2285): #14 GestureBinding._handlePointerEvent (package:flutter/src/gestures/binding.dart:156:7) I/flutter ( 2285): #15 GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:102:7) I/flutter ( 2285): #16 GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:86:7) I/flutter ( 2285): #20 _invoke1 (dart:ui/hooks.dart:274:10) I/flutter ( 2285): #21 _dispatchPointerDataPacket (dart:ui/hooks.dart:183:5) I/flutter ( 2285): (elided 3 frames from package dart:async) I/flutter ( 2285): Handler: "onTap" I/flutter ( 2285): Recognizer: I/flutter ( 2285): TapGestureRecognizer#8dd5e I/flutter ( 2285): ════════════════════════════════════════════════════════════════════════════════════════════════════

版本信息如下: ➜ first_flutter_app flutter --version Flutter 1.14.6 • channel unknown • unknown source Framework • revision fabeb2a16f (5 个月前) • 2020-01-28 07:56:51 -0800 Engine • revision c4229bfbba Tools • Dart 2.8.0 (build 2.8.0-dev.5.0 fc3af737c7)

andyli386 avatar Jun 30 '20 15:06 andyli386