Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly use redux with react-native navigation

I have been trying to do a setup using react-native-router-flux and followed the steps. Then tried to follow the examples and also logging a lot of info to try to reverse engineer it to work. However even following all the information I could find I ended up with some weird state structure:

enter image description here

scene is a object containing the router state. However initial state is replicated inside scene (so it contains again devices and rooms objects).

If I change the ordinary state devices or routes it throws an error as: Key <name of the key> has already been defined (other people reporting the same problems here).

So my question is: How do you route your react native apps with redux? Do you use other libraries? Are there any examples or documented resources I could use to fix my code?

Think that it has a typical redux structure. For the sake of the example, this is how it looks on my app/index.js:

import React, { Component } from 'react'
import { Router, Scene } from 'react-native-router-flux'
import { createStore, applyMiddleware, compose } from 'redux'
import { Provider, connect } from 'react-redux'
import logger from 'redux-logger'

import reducers from './reducers'
import Home from './components/home'
import Device from './components/devices'
import Login from './components/login'

const middleware = [logger()]
const store = compose(
  applyMiddleware(...middleware)
)(createStore)(reducers)

const RouterWithRedux = connect(reducers)(Router)

export default class AppContainer extends Component {
  render () {
    return (
      <Provider store={store}>
        <RouterWithRedux>
          <Scene key='login' component={Login} title='Login' />
            <Scene key='root' initial={true}>
            <Scene key='home' component={Home} title='Home' />
            <Scene key='device' component={Device} title='Device' />
          </Scene>
        </RouterWithRedux>
      </Provider>
    )
  }
}
like image 435
jsdario Avatar asked Oct 18 '22 03:10

jsdario


2 Answers

by my suffering experiences, there is no way to prevent Router re-render if you wrap it under a Provider and listen updates from redux, it is a nature by design.

the point how to prevent this, is: Router should render once and just once it means:

If you didn't connect to redux at all, it works fine since your Router would not be triggered by any of updates from redux.

Also, you can connect() Router to redux to get a dispatch() method props but you can NOT listen to another props.

Thus, the architecture would be:

import {
    Router,
    Scene,
    Actions,
} from 'react-native-router-flux';


// --- child component can connect and listen to props they want.
const myConnectedMainConponent = connect()(myMainConponent);
const myConnectedLoginConponent = connect()(myLoginConponent);

// --- Create it via Actions.create(), or it will be re-created for each render of your Router
const scenes = Actions.create(
    <Scene key="root">
        <Scene key="login" component={myLoginConponent} />
        <Scene key="main" component={myMainConponent} />
    </Scene>
);

// --- Create connected Router if you want dispatch() method.
// --- Or you can just use vanilla Router
const myConnectedRouter = connect()(Router);

// --- your exported main router
export default class MyExportedRouter extends React.Component {
    constructor(props) {
        super(props);
    };

    render() {
        return (
            <Provider store={store}>
                <myConnectedRouter scenes={scenes} />
            </Provider>
        );
    }
}

p.s. I typed above codes directly here, be aware the syntax error :)

Point Taken:

  1. Router should render once and just once ( connect to get dispatch method only or not connect at all )
  2. pre create scenes via Actions.create() and pass it into Router
  3. move your app main logic into one of the children of Router

=====================

this is originally replied on https://github.com/aksonov/react-native-router-flux/issues/376#issuecomment-241965769

thanks @jsdario for mention here, hope this helps

like image 137
zxcpoiu Avatar answered Oct 21 '22 01:10

zxcpoiu


I'm using only redux and react-redux. Creating a store with createStore with some middlewares (after doing combineReducers):

const store = createStore(
  rootReducer,
  compose(applyMiddleware(thunk, promiseMiddleware())),
);

Registering app:

AppRegistry.registerComponent('app', () => () => (
  <Provider store={store}>
    <MainComponent />
  </Provider>
));

Using state in components:

const mapStateToProps = (state) => ({
  isLoading: state.core.isLoading,
});

Connecting component to state using connect:

export default connect(mapStateToProps)(HomeScene);
like image 26
Radek Czemerys Avatar answered Oct 21 '22 01:10

Radek Czemerys