Closed ykrank closed 4 years ago
其实也可以用InheritedWidget 来解决吧
其实也可以用InheritedWidget 来解决吧
当InheritedWidget 更新,如果上层的state不更新的话,fish-redex就会使用缓存的widget,依赖InheritedWidget 的子widget会不会更新呢?
我写了一个简单的例子
import 'package:flutter/material.dart';
class TestInheritedWidget extends InheritedWidget {
TestInheritedWidget({@required this.counter, Widget child})
: super(child: child);
final TestClass counter;
static TestInheritedWidget of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<TestInheritedWidget>();
}
@override
bool updateShouldNotify(TestInheritedWidget oldWidget) {
return oldWidget.counter.value != counter.value;
}
}
class TestClass {
String name;
int value;
TestClass({this.name, this.value});
}
main.dart
import 'package:flutter/material.dart';
import 'package:movie/style/test_Inherited.dart';
import 'app.dart';
Future main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(TestInheritedWidget(
counter: TestClass(name: 'test', value: 1), child: await createApp()));
}
test_page.dart
import 'package:fish_redux/fish_redux.dart';
import 'package:flutter/material.dart';
import 'package:movie/actions/adapt.dart';
import 'action.dart';
import 'state.dart';
Widget buildView(
TestPageState state, Dispatch dispatch, ViewService viewService) {
return Scaffold(
appBar: AppBar(),
body: viewService.buildComponent('test'),
);
}
test_component.dart
import 'package:fish_redux/fish_redux.dart';
import 'package:flutter/material.dart';
import 'package:movie/actions/adapt.dart';
import 'package:movie/style/test_Inherited.dart';
import 'package:movie/views/test_page/action.dart';
import 'action.dart';
import 'state.dart';
Widget buildView(TestState state, Dispatch dispatch, ViewService viewService) {
return Center(
child: Column(
children: <Widget>[
SizedBox(height: Adapt.px(200)),
Text(
'${TestInheritedWidget.of(viewService.context).counter.value}',
key:
ValueKey(TestInheritedWidget.of(viewService.context).counter.value),
),
SizedBox(height: Adapt.px(100)),
FlatButton(
color: Colors.amber,
onPressed: () {
TestInheritedWidget.of(viewService.context).counter.value++;
dispatch(TestPageActionCreator.onAction());
},
child: Text('add'),
)
],
));
}
效果如下
我写了一个简单的例子
import 'package:flutter/material.dart'; class TestInheritedWidget extends InheritedWidget { TestInheritedWidget({@required this.counter, Widget child}) : super(child: child); final TestClass counter; static TestInheritedWidget of(BuildContext context) { return context.dependOnInheritedWidgetOfExactType<TestInheritedWidget>(); } @override bool updateShouldNotify(TestInheritedWidget oldWidget) { return oldWidget.counter.value != counter.value; } } class TestClass { String name; int value; TestClass({this.name, this.value}); }
main.dart
import 'package:flutter/material.dart'; import 'package:movie/style/test_Inherited.dart'; import 'app.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); runApp(TestInheritedWidget( counter: TestClass(name: 'test', value: 1), child: await createApp())); }
test_page.dart
import 'package:fish_redux/fish_redux.dart'; import 'package:flutter/material.dart'; import 'package:movie/actions/adapt.dart'; import 'action.dart'; import 'state.dart'; Widget buildView( TestPageState state, Dispatch dispatch, ViewService viewService) { return Scaffold( appBar: AppBar(), body: viewService.buildComponent('test'), ); }
test_component.dart
import 'package:fish_redux/fish_redux.dart'; import 'package:flutter/material.dart'; import 'package:movie/actions/adapt.dart'; import 'package:movie/style/test_Inherited.dart'; import 'package:movie/views/test_page/action.dart'; import 'action.dart'; import 'state.dart'; Widget buildView(TestState state, Dispatch dispatch, ViewService viewService) { return Center( child: Column( children: <Widget>[ SizedBox(height: Adapt.px(200)), Text( '${TestInheritedWidget.of(viewService.context).counter.value}', key: ValueKey(TestInheritedWidget.of(viewService.context).counter.value), ), SizedBox(height: Adapt.px(100)), FlatButton( color: Colors.amber, onPressed: () { TestInheritedWidget.of(viewService.context).counter.value++; dispatch(TestPageActionCreator.onAction()); }, child: Text('add'), ) ], )); }
效果如下
key必须要绑定依赖数据吗
不需要的,你可以自己尝试下
不需要的,你可以自己尝试下
你是不是在TestPageActionCreator.onAction()中刷新了整个page的state或者TestState呀。
我因为user是全app通用的,所以没办法一个个页面的手动刷新,希望user改了后,用到user的component或者page会自己刷新,而不是我得一个个去手动刷新。另外将shouldUpdate改成了按equal来判断后,刷新state时也不会走到buildView,导致压根不刷新。感觉放在shouldUpdate里也是一个办法,不过没找到拿oldStore和现在的store的办法。
是全局刷新的,你可以自己尝试一下 account_page.dart 代码片段
Text(
'Hi , ${state.user?.displayName ?? 'Guest'}+${TestInheritedWidget.of(viewService.context).counter.value}',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: Adapt.px(60),
),
),
是全局刷新的,你可以自己尝试一下 account_page.dart 代码片段
Text( 'Hi , ${state.user?.displayName ?? 'Guest'}+${TestInheritedWidget.of(viewService.context).counter.value}', style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: Adapt.px(60), ), ),
试了,test直接用了你的代码还是无效,buildView不会重新进入,只有自己手动更新page的state才能触发刷新。所以我才问你TestPageActionCreator.onAction()中是否刷新了整个page的state或者TestState。 这还是我问的第一个问题,Component的shouldUpdate因为不包括这个全局数据的判断,导致返回了false。 你那边之所以有效,是因为你Reducer里clone了当前state,而默认的shouldUpdate是identical判断,那自然是返回了true,整个page都会重建的。而我现在就是需要局部重建,因此不能直接重建整个page。即使只能全部重建,也不应该是自己手动去修改page state。
确实,如果组件设置了shouldUpdate的条件,由于InheritedWidget的数据并不在对应组件的state中,shouldUpdate是判断不了,这样就不能刷新
这种情况,简单的方法我建议也是通过 InheritedWidget 来完成。
fish-redux 在顶级InheritedWidget发生变化时,默认会触发一次缓存的清理。
void didChangeDependencies() {
super.didChangeDependencies();
if (widget.component.protectedClearOnDependenciesChanged != false) {
_ctx.clearCache();
}
_ctx.onLifecycle(LifecycleCreator.didChangeDependencies());
}
didChangeDependencies
原来如此,我看到clearOnDependenciesChanged默认是false,改成true就行了。
如果 clearOnDependenciesChanged 默认是false,看上去是一个不合理的选择,我会在下个版本中,修改它的默认值。
如果组件要用到全局的数据,有没有更好的方法。从 page 一直往下传太蛋疼了
如果组件要用到全局的数据,有没有更好的方法。从 page 一直往下传太蛋疼了
InheritedWidget。记得将page和component的clearOnDependenciesChanged设成true。
如果组件要用到全局的数据,有没有更好的方法。从 page 一直往下传太蛋疼了
InheritedWidget。记得将page和component的clearOnDependenciesChanged设成true。
可以给个demo么?
如果组件要用到全局的数据,有没有更好的方法。从 page 一直往下传太蛋疼了
InheritedWidget。记得将page和component的clearOnDependenciesChanged设成true。
请问这个方法怎么设置 我没有找到对应的入口
现在有一个全局对象,比如User。所有的component都有可能用到,并且都会随它的修改而更新。按照fish-redux的设计,我目前是使用reselect,但意味着从page开始到所有的component的state,都需要包裹一层user。虽然我目前是用通用mixin,但是每个state都不得不包裹一层,哪怕自己没用到,子component也有可能用到,还得一层层reselect下去,从性能和设计考虑,都显得实在太臃肿了。 这个现在有什么好的解决方案?或者对框架有所修改,比如加入订阅机制,component可以订阅某个修改。或者换种方式,将connectExtraStore下移到component,使用类似的数据流。