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?
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 tocomponentWillMount
.
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
};
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