Closed zjuwjf closed 5 years ago
1,拓展
水平上的,增加全局Store的支持,类比vue的渐进开发思路,fish redux可以像传统redux那样使用,也可以搭配adapter作更极致的单页面优化。
2,插件
增加类似React dev tool这样的chrome 插件,可以对state检视,action时空穿梭,但现在的observatory也能凑合用。
3,问题
fish redux的注释和文档🌰可以更好
4,期望
在专业,友善,耐心,尊重氛围下推进,并能体现这些的开源产品。国际化,也期望它能像vue那样得到国内外工程师的认可和喜爱。
补充一个flutter的痛点-hotfix
1,拓展
全局的监听器或者是 全局store的管理,(目前认为纯flutter 的项目开发需要这样的全局管理);
3,问题
同扩展,我要全局管理,我们目前正在尝试使用 flutter provide 结合fish-redux 来解决;
3.问题 文档没有完全讲清楚,应该多使用一些图表说明原理。example中示例需要增加,作为一个标准框架,基本的示例必不可少,这样可以帮助新人快速上手。
4.未来 希望能成为Flutter业界标准框架,向vue学习,不断自我完善推进。
3.问题 文档!文档!!文档!!! 确实现在的文档不完善,一些用法和有些字段只有在源代码中能看到。其次就是demo,demo不一定要多复杂,展示基本用法即可。在一个就是上面说的全局状态管理了。
4.未来 因为是从RN转过来的,所以在使用了dva框架之后,觉得用起来很舒服,因此,我觉得可以借鉴dva的一些东西,让Fish-Redux更完善和人性化
请问一个页面里面包含了 TabController , 这个应该怎么写? 我尝试写成这样 但是报错 没办法实现 TickerProviderStateMixin
class PageState with Cloneable<PageState>, TickerProviderStateMixin {
TabController tabController;
@override
PageState clone() {
return PageState()..tabController = tabController;
}
}
PageState initState(Map<String, dynamic> args) {
PageState state = PageState();
TabController tabController = TabController(vsync: state, length: 2);
state.tabController = tabController;
return state;
}```
请大牛给出解法,谢谢~!
请问一个页面里面包含了 TabController , 这个应该怎么写? 我尝试写成这样 但是报错 没办法实现 TickerProviderStateMixin
class PageState with Cloneable<PageState>, TickerProviderStateMixin { TabController tabController; @override PageState clone() { return PageState()..tabController = tabController; } } PageState initState(Map<String, dynamic> args) { PageState state = PageState(); TabController tabController = TabController(vsync: state, length: 2); state.tabController = tabController; return state; }``` 请大牛给出解法,谢谢~!
文档文档,我需要文档和更多的demo啊
State应更好的支持final属性! 而不是像现在这样,得在initState或connector里面像变魔术那样搞些垃圾“技巧代码”。 别跟我说final属性用不到!
State应更好的支持final属性! 而不是像现在这样,得在initState或connector里面像变魔术那样搞些垃圾“技巧代码”。 别跟我说final属性用不到!
就个别问题,建议是搜索老的issue,或者新开一个。很大可能,你的问题是有讨论过的。 无论如何,在github上,我们是在讨论问题,而不是来发泄情绪。
框架注释太少了啊,能给个你们框架设计图吗,lib库中的类之间的关系,现在分析源码都不好分析啊!
就个别问题,建议是搜索老的issue,或者新开一个。很大可能,你的问题是有讨论过的。 无论如何,在github上,我们是在讨论问题,而不是来发泄情绪。
也许你认为更好的支持final属性,是无关紧要的个别问题。 但无论从哪个意义上讲,这的确是我认为的能够提升你们这个框架的一个很重要的能力。
除了final属性外。框架能否提供静态工具方法,使statelesswidget更好地被应用。比如viewservice, dispach,context能够在statelesswidget中更简便的获得,而非必须使用statelesswidget的构造方法参数。
就个别问题,建议是搜索老的issue,或者新开一个。很大可能,你的问题是有讨论过的。 无论如何,在github上,我们是在讨论问题,而不是来发泄情绪。
也许你认为更好的支持final属性,是无关紧要的个别问题。 但无论从哪个意义上讲,这的确是我认为的能够提升你们这个框架的一个很重要的能力。
如果你说的是immutable-state,那么它是已经在fish-redux中得到支持的。如果你说的是其他问题,那么需要将问题客观的描述清楚。
0-0大佬,你好! 有个不是fish_redux的问题,我想了解下咸鱼动态化方面的,但是找不到什么路径,我详细看了2篇关于这个的文章,目前遇到问题:1,final String name = ASTUtils.getNodeString(namedExp.name); if (name == 'children') { continue; }时为children为什么要跳过去呢,第一篇文章说widget 的children 放在list里面,但是并没有看到这样的步骤啊.如果可以想看下ASTUtils代码具体片段. 2,FunctionExpressionParser.parse(namedExp.expression)能否详细让看下呢,不太清楚这个步骤是把方法解析成什么返回回来,解析出的方法返回值,在客户端怎么用呢 3,交互事件怎么做动态化?这部分感觉很难懂的! 感觉自己好菜0-0,只能求助了!实在找不到方向0-0,能帮助下吗,感谢!
3.问题 文档!文档!!文档!!! 确实现在的文档不完善,一些用法和有些字段只有在源代码中能看到。其次就是demo,demo不一定要多复杂,展示基本用法即可。在一个就是上面说的全局状态管理了。
4.未来 因为是从RN转过来的,所以在使用了dva框架之后,觉得用起来很舒服,因此,我觉得可以借鉴dva的一些东西,让Fish-Redux更完善和人性化
兄弟,我也是,感觉dva用的特别爽
是否考虑支持 redux-persist 类似的功能?
@baij930312 我在APP中做了个集成 fish_redux 和 redux-persist的 middleware,这种相关代码片段
final persistor = Persistor<PageState>(
storage: FlutterStorage(),
serializer: JsonSerializer<PageState>(PageState.fromJson),
);
Middleware<PageState> persistMiddleware = (
{Dispatch dispatch, Get<PageState> getState}) {
return (Dispatch next) {
return (Action action) {
next(action);
if (action is PersistAction) {
print('PersistState: ${action.type} ${action.payload}');
persistor.save(getState());
}
};
};
};
var initialState;
try {
initialState = await persistor.load();
} on SerializationException {
// 第一次加载程序时,还没有任何数据,加载数据会失败
// 此时使用初始化数据
initialState = PageState();
}
@baij930312 我在APP中做了个集成 fish_redux 和 redux-persist的 middleware,这种相关代码片段
final persistor = Persistor<PageState>( storage: FlutterStorage(), serializer: JsonSerializer<PageState>(PageState.fromJson), ); Middleware<PageState> persistMiddleware = ( {Dispatch dispatch, Get<PageState> getState}) { return (Dispatch next) { return (Action action) { next(action); if (action is PersistAction) { print('PersistState: ${action.type} ${action.payload}'); persistor.save(getState()); } }; }; }; var initialState; try { initialState = await persistor.load(); } on SerializationException { // 第一次加载程序时,还没有任何数据,加载数据会失败 // 此时使用初始化数据 initialState = PageState(); }
cool~ 你是基于整个app只有一个store的策略下的嘛,另外如果要支持这种功能的话所有的state都需要支持fromJson和toJson了吧
是的,我只有一个store需要存储,这个store下所有的state 都做了fromJson和toJson,另外我并非所有的action都需要触发存储,就做了个叫 PersistAction Action子类,只有PersistAction才触发save动作。
如果我需要在state之上在加一个计算层,该如何实现,比如api返回的数据比较零碎,我需要将需要将多个model的数据进行组装之后才可以在ui层演示这个没有没考虑加一个回调让用户自己来处理
如果我需要在state之上在加一个计算层,该如何实现,比如api返回的数据比较零碎,我需要将需要将多个model的数据进行组装之后才可以在ui层演示这个没有没考虑加一个回调让用户自己来处理
这里就是effect中做的事情。
如果我需要在state之上在加一个计算层,该如何实现,比如api返回的数据比较零碎,我需要将需要将多个model的数据进行组装之后才可以在ui层演示这个没有没考虑加一个回调让用户自己来处理
依照我最近对fish-redux源码的研究,作者好像是想要开发者在connector里面去做我上面提到的问题
3 问题: 3.1 文档比较零散,很多关键问题,比如调用的一些关键时序图没有,实际投入使用看得比较累
4 未来: 4.1 需要一个比较有更多内容的例子来引导新人使用 4.2 更多的参考dva的设计,fish-redux这一层的所做的其实参考dva能够做得更好,如 loading状态的设计,可以简化很多手写的 success、failure Action的处理 4.3 全局store目前的设计比较破坏原有的结构,导致page initialState功能闲置,需要更加内聚的方式代替action的方式
ViewService的buildComponent希望添加extra参数,同样的,在对应的Dependent的buildComponent,和connector中也添加extra参数。 现在存在一种需求,不定数量的component复用,在state中对应存储的数据格式为list或者map<key, value>。这时候需要在buildComponent和connector中指定具体的key来获取正确的数据。
ViewService的buildComponent希望添加extra参数,同样的,在对应的Dependent的buildComponent,和connector中也添加extra参数。 现在存在一种需求,不定数量的component复用,在state中对应存储的数据格式为list或者map<key, value>。这时候需要在buildComponent和connector中指定具体的key来获取正确的数据。
添加了extra参数,本质上数据就不单一了。你具体讲下你的场景么?
ViewService的buildComponent希望添加extra参数,同样的,在对应的Dependent的buildComponent,和connector中也添加extra参数。 现在存在一种需求,不定数量的component复用,在state中对应存储的数据格式为list或者map<key, value>。这时候需要在buildComponent和connector中指定具体的key来获取正确的数据。
添加了extra参数,本质上数据就不单一了。你具体讲下你的场景么?
我上面已经解释了呀,同一page有不定数量的component复用,它们的数据完全是来自于store里面的一个list,list的每一条对应一个component,目前考虑extra里面是放能标识component实例和对应数据的key,只是考虑扩展,使用extra。 从数据层面讲,你可以认为是更高形式的Adapter。不能使用Adapter的原因是使用了AppRoute之后,每一个page都是component,完全有可能是list的每一条对应一个page。 这个和单一数据也并不冲突。
ViewService的buildComponent希望添加extra参数,同样的,在对应的Dependent的buildComponent,和connector中也添加extra参数。 现在存在一种需求,不定数量的component复用,在state中对应存储的数据格式为list或者map<key, value>。这时候需要在buildComponent和connector中指定具体的key来获取正确的数据。
添加了extra参数,本质上数据就不单一了。你具体讲下你的场景么?
我上面已经解释了呀,同一page有不定数量的component复用,它们的数据完全是来自于store里面的一个list,list的每一条对应一个component,目前考虑extra里面是放能标识component实例和对应数据的key,只是考虑扩展,使用extra。 从数据层面讲,你可以认为是更高形式的Adapter。不能使用Adapter的原因是使用了AppRoute之后,每一个page都是component,完全有可能是list的每一条对应一个page。 这个和单一数据也并不冲突。
+1
可以获取异步effect的状态吗,比如我做登陆功能,然后点击提交后获取对应的effect应该是loading状态,当服务器返回数据effect代码运行完以后,effect的状态获取为done
可以获取异步effect的状态吗,比如我做登陆功能,然后点击提交后获取对应的effect应该是loading状态,当服务器返回数据effect代码运行完以后,effect的状态获取为done
ctx.state
可以获取最新的状态
诚心请教:能不能讲讲为什么选择了Redux而没有选择BLoC,是BLoC在技术上有什么缺陷吗?
我上面已经解释了呀,同一page有不定数量的component复用,它们的数据完全是来自于store里面的一个list,list的每一条对应一个component,目前考虑extra里面是放能标识component实例和对应数据的key,只是考虑扩展,使用extra。 从数据层面讲,你可以认为是更高形式的Adapter。不能使用Adapter的原因是使用了AppRoute之后,每一个page都是component,完全有可能是list的每一条对应一个page。 这个和单一数据也并不冲突。
1、 推荐使用PageRoutes 2、数据驱动的扩展 #239
fish-redux 的数据驱动是store 扁平的通知到各个组件。
默认是根据组件的state是不是同一个对象的引用来决定。(除非我们自定义shouldUpdate) 这里会有几个关注点: a)如果我们直接修改state.field 将会判断为同一个对象,所以我们需要clone或其他手段,在reducer函数中返回新的state。(它的上级state,上上级state的clone,是框架自动会处理的)。 b)组件的state如何而来?它是通过我们配置的connector.get 而来。如果我们的get函数永远返回一个新的对象,它不是最佳实践,带来多余的组件刷新。这种情况下要考虑使用reselect来将上级state的若干要素,只有在对应要素发生变化的情况下才会生成新的下级state。
组件如何确定自己要刷新 这里和上面的规则是一样的
如何让appstore的变化也能精确驱动组件的变化 这里的精确指的是,只有在对应要素发生变化的时候才发生刷新。 a)将AppState 和 PageState 进行链接, 当AppState里有PageState关心的要素发生变化时,自动计算出最新PageState。 b)PageState的精确变化,驱动关心了PageState里对应要素的任意组件发生刷新。 这个过程是精确而清晰的。
fish-redux中的数据驱动的核心是connector。
老哥你好。最近遇到一个问题,每一个componen的state都会有一个overirde的clone方法。我不知道当时设计考虑到什么,但开发体验上,每个clone都需要去级联赋值,如果state多的话,这是一个耗时的重复性操作。我觉得对于clone方法没有必要去override。
如果要内置处理clone的话,需要遍历原state class的field。这一块可能会用到reflectable这个包。
下午试了一下。成本有点高。需要引入两个包。新增一个State基类。然后页面的state类通过reflectable做映射。还有运行前先要build一个映射文件。
老哥你好。最近遇到一个问题,每一个componen的state都会有一个overirde的clone方法。我不知道当时设计考虑到什么,但开发体验上,每个clone都需要去级联赋值,如果state多的话,这是一个耗时的重复性操作。我觉得对于clone方法没有必要去override。
如果要内置处理clone的话,需要遍历原state class的field。这一块可能会用到reflectable这个包。
下午试了一下。成本有点高。需要引入两个包。新增一个State基类。然后页面的state类通过reflectable做映射。还有运行前先要build一个映射文件。
老哥,我现在的做法是,配合dart的analyzer和build库,进行自动化生成clone方法,基本上你在state修改或者添加属性都能实时监测到生成新的clone方法,而且不需要运行时,对于性能没有任何影响
老哥你好。最近遇到一个问题,每一个componen的state都会有一个overirde的clone方法。我不知道当时设计考虑到什么,但开发体验上,每个clone都需要去级联赋值,如果state多的话,这是一个耗时的重复性操作。我觉得对于clone方法没有必要去override。 如果要内置处理clone的话,需要遍历原state class的field。这一块可能会用到reflectable这个包。 下午试了一下。成本有点高。需要引入两个包。新增一个State基类。然后页面的state类通过reflectable做映射。还有运行前先要build一个映射文件。
老哥,我现在的做法是,配合dart的analyzer和build库,进行自动化生成clone方法,基本上你在state修改或者添加属性都能实时监测到生成新的clone方法,而且不需要运行时,对于性能没有任何影响
老哥能不能弄个demo看一下。
可以获取异步effect的状态吗,比如我做登陆功能,然后点击提交后获取对应的effect应该是loading状态,当服务器返回数据effect代码运行完以后,effect的状态获取为done
ctx.state
可以获取最新的状态
我说的是获取异步effect的执行状态哦,从哪里看
可以获取异步effect的状态吗,比如我做登陆功能,然后点击提交后获取对应的effect应该是loading状态,当服务器返回数据effect代码运行完以后,effect的状态获取为done
ctx.state
可以获取最新的状态
我说的是获取异步effect的执行状态哦,从哪里看
我的登陆目前是这样写的
_login(Action action, Context<SignInState> ctx) async {
try {
// final uid = ctx.state.uidController.text;
if (uid == '') {
throw new Exception('请输入账号');
}
// final pwd = ctx.state.pwdController.text;
if (pwd == '') {
throw new Exception('请输入密码');
}
ctx.dispatch(SignInActionCreator.loading(true));
final res = await api.user.auth(uid, pwd);
if (res.error) {
throw new Exception(res.message);
}
final user = res.data;
globalStore.dispatch(GlobalActionCreator.cacheUserInfo(user));
api = Api.auth(user.token);
Navigator.of(ctx.context).pushReplacementNamed('home');
} catch (e) {
errorDialog(e.message, ctx.context);
} finally {
if (ctx.state.loading) {
ctx.dispatch(SignInActionCreator.loading(false));
}
}
}
可以获取异步effect的状态吗,比如我做登陆功能,然后点击提交后获取对应的effect应该是loading状态,当服务器返回数据effect代码运行完以后,effect的状态获取为done
ctx.state
可以获取最新的状态
我说的是获取异步effect的执行状态哦,从哪里看
我的登陆目前是这样写的
_login(Action action, Context<SignInState> ctx) async { try { // final uid = ctx.state.uidController.text; if (uid == '') { throw new Exception('请输入账号'); } // final pwd = ctx.state.pwdController.text; if (pwd == '') { throw new Exception('请输入密码'); } ctx.dispatch(SignInActionCreator.loading(true)); final res = await api.user.auth(uid, pwd); if (res.error) { throw new Exception(res.message); } final user = res.data; globalStore.dispatch(GlobalActionCreator.cacheUserInfo(user)); api = Api.auth(user.token); Navigator.of(ctx.context).pushReplacementNamed('home'); } catch (e) { errorDialog(e.message, ctx.context); } finally { if (ctx.state.loading) { ctx.dispatch(SignInActionCreator.loading(false)); } } }
非常优雅的代码。
有个小问题,你的异常处理在哪里?
catch里。会把错误信息通过dialog显示出来,没做其他的操作。我是不是少了返回一个非空值让事件不再传递?
嗯,并不需要额外的非空值的返回, combineEffects -api 会补上非空值。
我看错了,我原以为是在外部会有一个统一的面向业务异常的处理中心。
注释。。求注释。。对于没有用过redux的端同学来说,注释太少读起源吗来太难受了~
typedef TypedApplyLike<R> = R Function(List<dynamic>, [Map<Symbol, dynamic>]);
/// Unified abstraction of functions which used in [Function.apply]
typedef ApplyLike = dynamic Function(List<dynamic>, [Map<Symbol, dynamic>]);
/// Unified abstraction of function AOP, input one function output another with some enhancement inside.
typedef ApplyLikeEnhancer = ApplyLike Function(ApplyLike functor);
ApplyLike _identity(ApplyLike f) => f;
ApplyLikeEnhancer _combine(ApplyLikeEnhancer e0, ApplyLikeEnhancer e1) =>
(ApplyLike f) => (e1 ?? _identity)((e0 ?? _identity)(f));
顶层的文档太少了,代码看起来有点吃力……
1.能力拓展:
(it is no urgely)
1.1根据 page 自动生成route? source from umi
1.2
如果A是B的子集,那么有一种方法可以生成实现get、set的defaultconn。
A[a,b,c,d,e] B[b,c]
注释。。求注释。。对于没有用过redux的端同学来说,注释太少读起源吗来太难受了~
1.能力拓展: (it is no urgely) 1.1根据 page 自动生成route? source from umi 1.2 如果A是B的子集,那么有一种方法可以生成实现get、set的defaultconn。 A[a,b,c,d,e] B[b,c]
- dependencies is not simple once I am,at a loss,learning about pool and slots ....
感谢反馈。 1.1 目前路由层是比较简易的,但是暂时没有规划fish-redux会完整的自己去实现一次路由层,我们的设计目标是能按需结合其他的路由框架。
1.2 conn的部分 ,建议可以单独开一个issue,来讨论是否当前已经是足够了,还是有必要继续提升。
1.3 的部分,目前在整理一部分的内部实现和增加注释, 期望更加易懂易用。
typedef TypedApplyLike<R> = R Function(List<dynamic>, [Map<Symbol, dynamic>]); /// Unified abstraction of functions which used in [Function.apply] typedef ApplyLike = dynamic Function(List<dynamic>, [Map<Symbol, dynamic>]); /// Unified abstraction of function AOP, input one function output another with some enhancement inside. typedef ApplyLikeEnhancer = ApplyLike Function(ApplyLike functor); ApplyLike _identity(ApplyLike f) => f; ApplyLikeEnhancer _combine(ApplyLikeEnhancer e0, ApplyLikeEnhancer e1) => (ApplyLike f) => (e1 ?? _identity)((e0 ?? _identity)(f));
顶层的文档太少了,代码看起来有点吃力……
你反馈的是AOP的源码的部分,建议可以就这个问题,单独开一个issue, 在讨论中,我们可以完善注释和文档, 使其易读易懂易用。
注释。。求注释。。对于没有用过redux的端同学来说,注释太少读起源吗来太难受了~
可以就具体的哪一块注释的缺失,提issue,在讨论中,我们可以完善注释和文档, 使其易读易懂易用。
希望可以添加 观察者模式
希望可以添加 观察者模式
能具体说下么,建议新开一个issue把。
使用fish-redux,多语言咋办呢?如果用他原生的方式是好整的,但是用了fish-redux不会触发更新。如果我要每次在Effect中去拦截,强制性去更新一遍绑定的数据是可以的。但是每个页面都要设置一把,多写了很多重复的代码。
👏大家在这里发声,讨论。
拓展: 大家想要fish-redux做哪些能力拓展,水平的,垂直的?
工具: 大家对工具和插件的看法?
问题: fish-redux在大家使用中会遇到哪些问题 ? 哪些是目前大家使用flutter的普遍的痛点 ?
未来: 期望fish-redux成为一个什么样的开源产品