React-native-router-flux: Ability to provide the left/right navbar buttons from the rendered component

Created on 6 May 2016  路  26Comments  路  Source: aksonov/react-native-router-flux

The current set up of the buttons is not ideal. They have to be declared and hooked up to action callback at the global level. When customisation is needed at the component level i.e. component needs to hide or show the button or enable/disable it depending on its own state things get impossible to manage with the current setup. The component cannot register a local callback on the button press either.

Maybe there could be a way to provide a custom navbar renderer?

Or am I missing something and this is already feasible ?

Thank you .

Most helpful comment

@jrwm thanks it works

  componentDidMount() {
    Actions.refresh({renderLeftButton: this.renderLeftButton, renderRightButton: this.renderRightButton})
  }

  renderRightButton = () => {
    return (
      <TouchableOpacity onPress={this.onAddAccount}>
         <Text>Save</Text>
      </TouchableOpacity>
    )
  }

  onAddAccount = () => {
    const {accountInput: account, keyInput: key} = this.state;
    this.props.dispatch(addAccount(account, key));
    Actions.auth({type: 'reset'});
  }

All 26 comments

I found this piece of code in the NavBar.js

const renderLeftButton = selected.renderLeftButton ||
      selected.component.renderLeftButton ||
      this.renderLeftButton;
const renderRightButton = selected.renderRightButton ||
      selected.component.renderRightButton ||
      this.renderRightButton;

would this mean that the component by supplying renderRightButton function would be able to control whether the button is visible or not? Let me try - if this would this would be fantastic!

not much luck :(

@andpor I think you have to use a custom navbar for those buttons, and have that navbar in the component. I honestly am not sure how as I am trying to figure that same thing out and this plugin seems very powerful, useful, and time saving, but the documentation lacks and I don't know enough to contribute as a beginner, so I don't know how to use it very well..

I wish there was a video tutorial that goes over these different parts...

  • Integrating custom navbar for scene
  • Triggering scene methods from corresponding navbar buttons
  • Side bar drawer integration
  • Customizing bottom tabbar with icons, and top ones for content

If you're able to get it to work, please let us know how!

@andpor Component methods must be _static_.

@aksonov Can you share a snippet?

class MyAccount extends React.Component {
   static renderRightButton(props){
    return <Text>rightButton</Text>;
    }

@aksonov Thank you :+1:

@MovingGifts Hi do you find any good hints related to sidebar drawer integration? I am looking for detailed document on this topic as well. Thanks.

Why is this closed? There doesn't seem to be a good way for the scene component to specify any data or state necessary to be passed to the right or left buttons for the navigator. Am I missing something?

Though I can create and manipulate RightButton from Component by using static renderRightButton I cannot access the Component's state because the method is static. :( Any ideas?

You will get it from props passed to that static method :)

How do non static props get passed to a static method... this issue really shouldn't be closed. Components that want to modify navigation buttons are forced to reset the bar after being mounted.

@jeremyong, I'm curious to see how @aksonov will answer. One way I am thinking about this is to manage your state within a store (if using flux) or within your app-wide store (if using redux). So using redux, your onLeft or onRight handler would dispatch an action like this:

static onLeft(props) {
  props.dispatch(myAction());
}

Then in the action creator, use redux-thunk to get access to dispatch and getState

Yes this is possible and considered but if you want the top buttons to depend on state in the component itself, it seems heavy handed to export that state to the global store and import it back again. Because it's an intrinsically UI thing, you end up exporting state about user data. For example, what if I want the back button to start glowing if the user taps the screen quickly or something (silly example but hopefully gets the point across).

Hello all, could you tell me how to make renderRightButton aware of state of component? Is it possible at all?

I have component with form inputs in state, when I submit I dispatch action with those inputs, this all happens when user presses button that is rendered in NavBar.

  static renderRightButton(props) {
    return (
      <TouchableOpacity onPress={this.onAddAccount}>
         <Text>Save</Text>
      </TouchableOpacity>
    )
  }

  onAddAccount = () => {
    const {accountInput: account, keyInput: key} = this.state;
    this.props.dispatch(addAccount(account, key));
    Actions.auth({type: 'reset'});
  }

I understand that is not possible because the method is static, so how to accomplish this?

@ppiechota
you can define your button in your scene's componentDidMount

Actions.refresh({ renderRightButton: this.yourFunctionToRenderButton, onRight: this.yourButtonHandler, })

don't use static renderRightButton, and you don't need to use flux either

@jrwm thanks it works

  componentDidMount() {
    Actions.refresh({renderLeftButton: this.renderLeftButton, renderRightButton: this.renderRightButton})
  }

  renderRightButton = () => {
    return (
      <TouchableOpacity onPress={this.onAddAccount}>
         <Text>Save</Text>
      </TouchableOpacity>
    )
  }

  onAddAccount = () => {
    const {accountInput: account, keyInput: key} = this.state;
    this.props.dispatch(addAccount(account, key));
    Actions.auth({type: 'reset'});
  }

@ppiechota
I tried renderRightButton approach on Scene1. Now I enter Scene1 renderRightButton get called every frame. very bad slow animation.

Reason I am using renderRightButton from component is I want to do some calculation and change right button dynamically (ex: before login and after login) and image involved. At most I only needed 2 or 3 calls to this function. But now I have 16 calls.

Is there any way other way. Or is there anyway to skip render on back or something.

A total hack but at least it allows me to achieve the desired result and avoid double render of Actions.refresh:

// your scene
<Scene key="someKey"
       component={ SomeComponent }
       onRight={
         (state) => {
           // state.scene.navigationState.myData is { hello: 'world' }
         }
       } />

// your component
class SomeComponent extends Component {
  // ...
  handleButtonClick() {
    this.props.navigationState.myData = { hello: 'world' };
  }
  // ...
}

Note that it still doesn't allow you to change a visual button's representation on fly.. but at least you can customize the handler (pass variable or callback).

I'm currently not able to render left button in any case, not even using refresh (I need to do it from the component).

Anyone able to fix the issue?

componentDidMount(){
      Actions.refresh({ renderRightButton: this.renderRightButton  })
}

renderRightButton = () => {
      return <Text>Test</Text>
}

My code is as above and the button is not getting rendered. @aksonov please provide powerful docs for this kind of issues.

As far as I see it is not supported for v4, PR is welcome.

Any workaround in v4?

@jrwm thanks it works

  componentDidMount() {
    Actions.refresh({renderLeftButton: this.renderLeftButton, renderRightButton: this.renderRightButton})
  }

  renderRightButton = () => {
    return (
      <TouchableOpacity onPress={this.onAddAccount}>
         <Text>Save</Text>
      </TouchableOpacity>
    )
  }

  onAddAccount = () => {
    const {accountInput: account, keyInput: key} = this.state;
    this.props.dispatch(addAccount(account, key));
    Actions.auth({type: 'reset'});
  }

This doesnt work on my project :/
Is there any other method ?

any luck :(

Actions.refresh({
  title: "foo",
  right: () => (
    <View style={{ width: 10, height: 10, backgroundColor: "red" }} />
  )
});

"renderRightButton" didn't work. "right" works, though.

Was this page helpful?
0 / 5 - 0 ratings