All Articles

ReactNative的Navigation

0. 前言

ReactNative确实是一个不错的移动端研发工具,但作为一个Hybrid的解决方案,它必然有相当多的制约在里面。最主要的就是如果你对原生研发不熟悉,没办法自己制作原生功能到JS的桥接库的话,你就只能使用社区内提供的功能库。虽然现在RN的生态还算是不错的,但显然仍旧有大量的功能是无法靠直接拿来就用的库就能完美支持的。这还是比较奢侈的烦恼,在RN的生态里甚至有一些最基础的功能到现在都不能很好支持,比如我今天想要聊的Navigation。

1. 历史

Navigation,或者说是WEB领域更让人熟悉的词汇Router,是一个应用最基本的需求。RN在这块一开始只有一个很简单的Navigator组件,功能实在是简陋。于是大量第三方的组件就起来了,社区里还是有几款比较不错的Navigation组件。

我一开始使用的是aksonov/react-native-router-flux,基本上这货算是当时的事实标准了,写RN的基本上都使用这款组件来完成Navigation功能。

到了去年开始,几个版本的更新之后在RNRF的issues以及其他渠道大量的消息提到了FB官方制作的Navigation这个组件:Navigation for React Native。基本上所有的第三方Navigation都开始慢慢集成FB的Navigation库,等于是基于它进行二次开发和封装。于是我也慢慢开始了解,并从最近的RN版本升级工作开始,也集成了这个组件,并把RNRF替换了出去。

在一段时间的接触和使用之后,总结下里面的一些问题。

2. 问题

2.1 版本

到今天为止,该项目的版本还停留在v1.0.0-beta.12,时间点是Latest commit 5e075e1 on 20 Jul @skevy skevy 1.0.0-beta.12。仍未达到第一个稳定版本的release程度,后面的一系列问题也就可以理解了。

2.2 文档

该项目的文档应该说还是可以读的,但也仅止于此,能看懂,能照抄,但一些深入些的问题,以及一些稍微有点绕的概念,就非常需要你自己花时间做个sample一点点理解了。就这方面来说,这文档简直无用。

2.3 Redux绑定

众所周知,Redux是一个非常好用的生命周期管理工具,大量的React项目都视其为必需项。官方的文档里姑且是有针对性的内容的,例子:Example

但这个例子有很大的问题,官方给的例子过于简单,所有的东西百来行就写完了。一个真实应用的Redux使用复杂度远超其上,我在对接集成的时候就出了不少问题。后来还是参考了第三方的博客才解决了这个问题。

成功的范例:

const AppNavigator = StackNavigator({
    Init: {screen: Initialization},
    // ...
}, {
    initialRouteName: "Init",
    headerMode: "none"
});
const AppWithNavigationState = ({dispatch, nav}) => (
    <AppNavigator navigation={addNavigationHelpers({dispatch, state: nav})}/>
);
const mapStateToProps = state => ({
    nav: state.nav,
});
const AppConnected = connect(mapStateToProps)(AppWithNavigationState);

Reducers["nav"] = (state, action: NavigationAction) => { // Reducers => {[key: string]: Reducer}
    const newState = AppNavigator.router.getStateForAction(action, state);
    return newState || state;
};

const store = createStore(
    combineReducers(Reducers),
    applyMiddleware(thunk)
);

export class App extends Component<any, any> {
    render() {
        return (
            <Root>
                <Provider store={store}>
                    <AppConnected/>
                </Provider>
            </Root>
        );
    }
}

2.4 性能

看看这个帖子:StackNavigator has performance issues and renders too many screens

三月份的一个issue,开到现在都没解决。

2.5 Screen Stack问题

性能以及当前的很多功能问题说到底都是由于navigate的页面跳转会导致大量Screen被直接push到Screen Stack里,且当前的API设计无法维护该Stack的问题所导致的。现在的Push机制过于粗暴,会触发大量的新页面创建,导致渲染端的CPU及内存的问题,在App长时间运行之后必然会引起崩溃。引发的问题包括且不限于刚才在2.4中提到的那个issue。

这个问题现在是在:Add optional key to navigate action, allowing idempotent pushes #135 这个issue里进行集中处理。这么一个重量级,可以说是影响到组件存亡的问题,居然到现在都没有解决,真的是不能理解。

2.6 低效的开发

社区已经对这个库投注了大量的心血,但看不到官方对这块的重视。大量的issue,重量级功能的pull request放在那里很久没有得到更新。

类似:

3. 结论

简单来说,如果你要做的是一个玩票性质的RN应用(比如我),无所谓性能及特殊功能要求的话,那你大可尝试使用这个组件。但如果是正儿八经要做产品的,还是尽量自己封装原生的Navigation,做桥接库来的实际。

EOF

Published 2017/9/1

Some tech & personal blog posts