React-native-router-flux: Set navigationBarStyle Dynamically in a Scene's Lifecycle Hook

Created on 9 Aug 2016  ·  9Comments  ·  Source: aksonov/react-native-router-flux

I want to theme my scenes based on data retrieved from a database. The same scene could render a nav bar that is pink, purple, blue, etc., based on what the user has configured in their settings.

I do not know what the nav bar background color will be until the scene is called and data used to generate the scene is loaded, which I would prefer to write in the lifecycle hooks of the scene itself to keep all of the scene logic in one place, rather than scattered about.

Is it possible to set navigationBarStyle dynamically at the scene itself, i.e. within a lifecycle hook once data is fetched, rather than having to define it upfront at the router level where <Scene key="scene-name" /> is defined?

question

Most helpful comment

Yes, you can update props via Actions.refresh(). Example:
Actions.refresh({ renderRightButton: this._renderRightButton });
https://github.com/aksonov/react-native-router-flux/blob/master/docs/OTHER_INFO.md

All 9 comments

Similarly, I'm looking to use a dynamic right button on the navBar that renders an Action Sheet with actions that are dependent on data. Think... Follow userABC123; Block userABC123; etc. Is there a way to dynamically generate the onRight function within a lifecycle hook (i.e. after data is fetched) to produce a custom action sheet?

Yes, you can update props via Actions.refresh(). Example:
Actions.refresh({ renderRightButton: this._renderRightButton });
https://github.com/aksonov/react-native-router-flux/blob/master/docs/OTHER_INFO.md

@sheparddw is correct. In the same way you can update the navigationBarStyle with Actions.refresh({navigationBarStyle ... }).

Where should you put the Actions.refresh() call?
When I put the refresh call in my flux action (which is called when there should be a change to the style) It only updates the navbar style on the currently selected tab. When I switch tabs, it reverts to the old style.

The only component that updates whenever I switch tabs is my tabbar, so I tried putting the refresh in my Tabbar component in componentWillReceiveProps or componentWillUpdate. Then I get infinite recursion because every time it is refreshed, Tabbar gets new props and it refreshes again.

@aksonov would you mind commenting on this?

I was playing with Actions.refresh in my component, but I don't think that this is the correct way to dynamically update properties of the scene. Here are my findings.

// Note: I'm using an es6 class that extends Component

If we place Actions.refresh({title: 'drawer'}); in the constructor, then react complains with this:

Warning: setState(...): Cannot update during an existing state transition (such as within render or another component's constructor). Render methods should be a pure function of props and state; constructor side-effects are an anti-pattern, but can be moved to componentWillMount.

This is just a warning and we achieve the desired result. However there is a sideffect - the render function is called twice when we do this.

If we directly place this in the componentWillMount function, then react doesn't issue any warning, but render is also called twice.

If we do this in the constructor:
this.props.navigationState.title = 'test';

then react won't complain and our navigationBar title will be test. The render method will be called just once. The same goes for calling onRight, onRightTitle etc. Now the thing is according to this https://facebook.github.io/react/docs/jsx-spread.html#mutating-props-is-bad mutating props is bad.

So, you can either mutate props which is bad or you can call Actions.refresh and have sideeffects, such as rendering the component twice... Any ideas?

Any updates on this? I'm having the exact same problem trying to dynamically set navigationBarStyle depending on user props. Specifically I'm trying to change the background color of the navigation bar. Actions.refresh({navigationBarStyle ... }) does not work either.

<Scene key="myScene"
component={myComponent}
renderTitle={() => { return <NavigationBarTitle title="My Title"/>}}
sceneStyle={styles.scene}
navigationBarStyle={[styles.navBar, this.props.theme.backgroundColor]} <- backgroundColor not updating when state changes
onRight={this.pushNoticeFilter}/>

I've managed to dynamically render different titles and styles in my custom title component of the navigation bar, but navigationBarStyle is not listening to state changes.

Does this have something to do with RNRF ignoring re-renders of scenes, where it prints "Key myScene is already defined!"?

@mikaelrosquist @compojoom I'm using redux to store the "themes" that I fetch from the server. The easiest way I found to do dynamic navigation bar styles to just create a wrapper component.

import React, { Component } from 'react';
import { NavBar } from 'react-native-router-flux';
import Variables from 'market/app/styles/base';

class CircllyNavBar extends Component {
  render() {
    return (
      <NavBar {...this.props} navigationBarStyle={{ backgroundColor: Variables.BRAND_PRIMARY() }} />
    )
  }
}

export default CircllyNavBar;
<Scene key="search_form" title="Search"
    component={SearchForm}
    navBar={CircllyNavBar} />

@OhaiBBQ Thank you! Works perfectly! 👍

@mikaelrosquist No problem. One other thing I found interesting (as I'm new to React), was that you can set the default props of a RNRF Scene by using the defaultProps class property of a React Component.

class Scene extends RNRFScene { }

Scene.defaultProps = {
  navBar: CircllyNavBar
};
Was this page helpful?
0 / 5 - 0 ratings

Related issues

rafaelcorreiapoli picture rafaelcorreiapoli  ·  3Comments

tonypeng picture tonypeng  ·  3Comments

llgoer picture llgoer  ·  3Comments

VictorK1902 picture VictorK1902  ·  3Comments

maphongba008 picture maphongba008  ·  3Comments