React-native-router-flux: [Urgent] How to get CurrentScene?

Created on 14 May 2017  Â·  12Comments  Â·  Source: aksonov/react-native-router-flux

Version

  • react-native-router-flux v3.38.0
  • react-native v0.42.0

For the following Router code, how can I get Current Scene?

<Router>
   <Scene key='drawer' component={NavigationDrawer} open={false}>
     <Scene key='drawerChildrenWrapper' navigationBarStyle={Styles.navBar} titleStyle={Styles.title} leftButtonIconStyle={Styles.leftButton} rightButtonTextStyle={Styles.rightButton}>
       <Scene initial key='launch' component={Launch} title='Launch' hideNavBar />
     </Scene>
   </Scene>
</Router>

Most helpful comment

@blapi what about those that doesn't use redux to manage state? Or doesn't use redux at all

All 12 comments

I would like too @aksonov :p
It's a bit annoying that onEnter, onPop, onReplace & onPush don't work anymore.

yes, please, @aksonov. How can we get the current scene? It doesn't have to be the easiest way, just a reliable way of getting the scene the user is looking at.

You should use redux to do this, it's reliable and very easy to implement !

Connect your component to the router reducer, this way, using this.props.scene will give you your current scene infos (key, name, sceneKey, etc..), do as following :

First, create your router-reducer this way :

import { ActionConst } from 'react-native-router-flux'

const initialState = {
  scene: {}
}

export default function routerReducer(state = initialState, action) {
  switch (action.type) {
    case ActionConst.FOCUS:
      return { ...state, scene: action.scene }
    default:
      return state
  }
}

Combine it to your root-reducer (let's assume this is your index.js in your reducers directory) :

import { combineReducers } from 'redux'
import routerReducer from './router-reducer'

const rootReducer = combineReducers({
    routing: routerReducer(,)
        // other reducer here...
})

export default rootReducer

Your component name is Launch, then do a LaunchContainer of this component this way :

import { connect } from 'react-redux'
import Launch from '../presentationals/launch'

const mapStateToProps = (state) => {
  return { ...state.routing }
}

const LaunchContainer = connect(
  mapStateToProps
)(Launch)

export default LaunchContainer

Finally, in your app.js or I don't know what file you're using (filename is index.js for me), but the file where you implement your scenes, do this :

import React from 'react'
import { Router, Scene } from 'react-native-router-flux'
import { createStore, applyMiddleware } from 'redux'
import { Provider, connect } from 'react-redux'
import thunkMiddleware from 'redux-thunk'
import createLogger from 'redux-logger'
import rootReducer from './reducers'

import LaunchContainer from './containers/launch-container'

const ReduxRouter = connect()(Router)
const logger = createLogger() // helps you to read your state in the console
const store = createStore(rootReducer, applyMiddleware(thunkMiddleware, logger))

class App extends React.Component {
  render() {
    return (
      <Provider store={store}>
        <ReduxRouter>
          <Scene key='home' hideNavBar>
            <Scene initial key='launch' component={LaunchContainer} title='Launch' hideNavBar />
          </Scene>
        </ReduxRouter>
      </Provider>
    )
  }
}

export default App

With this, you shouldn't have worries to find your current scene, anywhen you need it in a component, do what I did for your component, and you will be able to know your current scene using this.props.scene :smile:

Organization of the files (to be clear on it)

.
+-- containers
|   +-- launch-container.js
+-- presentationals
|   +-- launch.js
+-- reducers
|   +-- router-reducer.js
|   +-- index.js (containing the rootReducer)
+-- index.js (containing App.js)

Or you can do as it's done there : https://github.com/aksonov/react-native-router-flux/blob/master/docs/REDUX_FLUX.md, I forgot there was an example as I implemented it a while ago

@blapi what about those that doesn't use redux to manage state? Or doesn't use redux at all

I don't know for this case...

I saw we were able to know it using Actions.currentRouter.currentRoute but it's not working on my end, it would be very helpful though to use Actions because when you log it, you can see there is all the scenes

@surendharreddy @pbassut you are not tied at all to Redux or any other methodology. The plugin provides you with a reducer method that injects the current state and action. You can then do your own logic and pass the current scene to the next one, it will be passed as props.

// Where you define your router

let currentRoute = ""

const createRouterReducer = params => {
  const defaultReducer = Reducer(params)
  return (state, action) => {
    currentRoute = action.key // e.g. LoginPage
    action = {..., currentRoute} // you can access this on the scene component through the props
    return defaultReducer(state, action)
  }
}

...

// pass that function to the router
    <Router createReducer={createRouterReducer}>

Hope this helps.

Update: I just saw that the props of the scene also contain a navigationState object, maybe that is enough?

@jeroenbourgois Unfortunately is not that simple.

I have a drawer, a modal and multiple push scenes.
Multiple different actions are dispatched upon a single push for a reason I don't know. The most notable and frequent being a drawer's refresh. I could just ignore those, sure.

Since multiple actions are dispatched and I don't know the order they will be dispatched in different cases, the solution you provided also won't work reliable. But, of course, I could filter out actions of the PUSH type, right? Yeah, sure.

Also not every action sends a key with it.

I ended up coming up with a solution that uses a lot ifs. And here it is:

const reducerCreate = params => {
    const defaultReducer = new Reducer(params);
    let onMatchDetails = false;
    let onSwipe = false;
    return (state, action) => {
        const isDrawer = !!action.scene && action.scene.name == 'drawer';
        if(action.type == ActionConst.PUSH){
            onMatchDetails = action.key == "matchDetails" && !!action.notification;
        }else if(onMatchDetails && action.type == ActionConst.BACK_ACTION){
            onMatchDetails = false;
        }
        if(!isDrawer && action.type == ActionConst.FOCUS){
            onSwipe = action.scene.sceneKey == 'swipe';
        }
        if(!onMatchDetails && onSwipe){
            BackgroundWorker.start();
        }else{
            BackgroundWorker.stop();
        }
        return defaultReducer(state, action);
    };
};

The onMatchDetails is the modal, while the onSwipe is where I want to start a backgroundWorker. While on a scene that's not the onSwipe scene, I want to turn it off.
This works, but it's ugly.

@jeroenbourgois Oh, and not being tied to redux methodology at all is not entirely true, right. I see a reducer being defined right there.
A simpler approach for me would be something like Actions.currentSceneKey or a method like Actions.is('myScene')

The word reducer != redux per se :)
On Mon, 22 May 2017 at 18:16, Patrick Bassut notifications@github.com
wrote:

@jeroenbourgois https://github.com/jeroenbourgois Oh, and not being
tied to redux methology at all is not entirely sure, right. I see a reducer
being defined right there.
A simpler approach for me would be something like Actions.currentSceneKey
or a method like Actions.is('myScene')

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/aksonov/react-native-router-flux/issues/1867#issuecomment-303147817,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAMWSBisXDGLtt3S-z1enP-qYBqFsPztks5r8bS8gaJpZM4NaRG4
.

You're right. But isn't reducers specific to redux/flux?

I don't understand why you're not using redux.. in your case it will be helpful and your problem will be solved in the next 10 minutes, + you'll optimize what you just showed us.

Use the example aksonov provided or what I showed you before and you'll get your current scene.

If your problem is that your file is not a "scene" so you can't access the props but you want to know what scene you're in, you can still export your store and import it so you'll get the currentScene. (store.getState().yourReducerName.scene.theSceneInfosYouWant)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

tonypeng picture tonypeng  Â·  3Comments

llgoer picture llgoer  Â·  3Comments

fgrs picture fgrs  Â·  3Comments

basdvries picture basdvries  Â·  3Comments

rafaelcorreiapoli picture rafaelcorreiapoli  Â·  3Comments