React Native / Redux应用程序

时间:2016-08-02 18:57:06

标签: performance navigation react-native redux react-redux

在使用Redux的大型React Native应用程序中导航期间,所有访问过的场景(来自导航堆栈的场景)都保持挂载状态。当从最后一个场景组件调度任何动作时,所有这些场景都接收道具并按照它们被访问的顺序进行渲染。它会导致调度和最后一次场景渲染之间的冻结和可见延迟。

对于导航,我使用的是react-native-router-flux,但原始的React Native Navigator也会遇到同样的问题。

视频Possible navigation issues in React Native/Redux app

代码react-redux-navigation-test

很高兴知道如何防止将道具传递给导航链中没有聚焦的组件。

目前我正在检查每个组件的shouldComponentUpdate,如果这个组件被聚焦(可见)并且在相反的情况下返回false。

有没有更好的解决方案?

5 个答案:

答案 0 :(得分:2)

我建议您使用场景和标题渲染方法中的导航索引计算当前场景和正在渲染的场景之间的场景距离。如果距离> 1返回null。

这应该会阻止渲染整个导航历史记录。对我来说没有任何意义,这种行为不是开箱即用的,而是存在的。

答案 1 :(得分:0)

我没有使用react-native-router-flux,但我确实有使用相当大的React Native和Redux应用程序的经验。我注意到,有时如果您使用的数据足够大,可能会导致明显的延迟,但这些数据主要限于在开发中工作。构建应用程序时,它通常会更快。看起来Redux在开发和生产模式方面做的事情有点不同。

关于仍在安装的导航堆栈中的场景,这是设计的。即使您currentRouteStack到另一个屏幕,这些先前的屏幕仍然会挂起,直到它们从currentRouteStack弹出或从@Column替换。

此外,值得注意的是您的模拟器处于慢动画模式。不确定你是否为了视频而这样做,但导航缓慢部分是由于这一点。如果不是故意的话,只是抬头。

我会在你构建它之后检查应用程序是如何运行的,并且在进一步解决性能问题之前它还没有处于开发模式。可能不是最终应用产品的问题。

答案 2 :(得分:0)

我会在这里走出困境,但你是否正在使用以下方法之一来阻止重新渲染?

  • PureComponents(我认为在React 15.3中添加)
  • 手动使用浅比较道具和状态使用shouldComponentUpdate方法。

默认情况下,除非您正确处理了shouldComponentUpdate,否则React会在更新时重新呈现所有组件。

我做了类似的事情而根本没有这些问题

答案 3 :(得分:0)

问题确实是整个导航堆栈已连接到商店(因为除非使用resetto或resetnavigation,否则不会卸载组件)

这里有什么值得我现在做的。 我一直在使用一个略微修改的react redux实现,它跳过了不在视图中的场景的更新(见下文)

要使用它,您需要:

在上下文中存储一个组件树的路径

我们为此

创建了一个包装器
const CurrentRoute = React.createClass({ 
childContextTypes : { currentRoute: PropTypes.object },
 getChildContext() {
 return { currentRoute: this.props.route } 
},
render() { return this.props.children; } 
})

并在渲染场景中使用它

<CurrentRoute route={route}><CurrentScene navigate={navigate} route={route} index={index} /></CurrentRoute>

然后,您可以访问已经渲染组件的路径。

将导航堆栈存储为单例 我们在configure scene

中使用此代码
let routeStack = [];
export const updateRouteStack = stack => routeStack = stack;

然后你可以使用这个稍微修改过的react-redux连接函数,如果组件在另一个组件树中呈现,那么它将跳过更新,然后是当前显示的组件树 (或类似的实施) https://github.com/reactjs/react-redux/compare/master...ganmor:master

也许可以打包这个,但我没有时间去研究它。如果有人想这样做.. 希望有所帮助

答案 4 :(得分:0)

我们通过简单地将所有屏幕包装在一个组件中来解决它。

我们有一个包装整个屏幕的ScreenView组件,我们传给它一个参数&#34; restrictRerendersToRoutes&#34;。

此屏幕连接到状态,我们更新处于状态的currentScrene并将其公开到此屏幕视图。

然后我们只是在屏幕处于后台时使用这个shouldComponentUpdate实现来限制重新呈现:

  shouldComponentUpdate(nextProps) {
    if (!_.empty(this.props.restrictRerendersToRoutes)) {
      return !!this.props.restrictRerendersToRoutes
        .find((routeKey) => routeKey === nextProps.currentScene.name);
    }

    return true;
  }