Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support of external navigation state (full redux support) #2115

Closed
rasmniel opened this issue Jul 26, 2017 · 56 comments
Closed

Support of external navigation state (full redux support) #2115

rasmniel opened this issue Jul 26, 2017 · 56 comments

Comments

@rasmniel
Copy link

rasmniel commented Jul 26, 2017

Solved: Integrating the router with Redux is now possible. Check out this repo for an example: https://github.com/rasmniel/rnrfSample

I'm using the react-native-router-flux library and I want to store the current scene on state.
The problem is that the events in the reducer don't fire when navigating.

The app starts up like this:

...
import {Scene, Router} from 'react-native-router-flux';
const ReduxRouter = connect()(Router);

import reducers from './reducers';
import Home from './components/home';
import Login from './components/login';
...

export default
class App extends React.Component {

    componentWillMount() {
        this.prepareStore();
    }

    render() {
        return (
            <Provider store={this.store}>
                <ReduxRouter>
                    <Scene key="root">
                        <Scene key="home" component={Home}/>
                        <Scene key="login" component={Login}/>
                        ...
                    </Scene>
                </ReduxRouter>
            </Provider>
        );
    }

    prepareStore() {
        const initialState = ...
        const enhancer = ... // <- Middleware
        this.store = createStore(reducers, initialState, enhancer);
        persistStore(this.store) ;
    }
}

My reducer looks like this (in routeReducer.js):

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

const INITIAL_STATE = {scene: {}};

export default (state = INITIAL_STATE, {type, scene}) => {
    switch (type) {

        console.warn(type); // <-- this line prints every time a reducer is called.

        case ActionConst.FOCUS:
            console.warn('Focus'); // <-- this line never prints.
            return {...state, scene};

        default:
            return state
    }
}

... and is combined like this (in reducers.js):

import { combineReducers } from 'redux';
...
import routeReducer from './route-reducer';

export default combineReducers({
    ...
    route: routeReducer,
});

No errors are raised and everything else works as expected - the router works fine for navigation and basic functionality, but none of the events are fired as expected.

I can't seem to find a solution to this problem anywhere. Am I missing a step? I followed the documentation in the library repo (I used docs/v3 as there seem to be no v4 docs yet), but I don't know if I misunderstood something or this is caused by some of the recent updates being pushed to the library (I'm currently on version 4.0.0-beta.14). Any help is appreciated - Thanks!

@aksonov
Copy link
Owner

aksonov commented Jul 26, 2017 via email

@rasmniel
Copy link
Author

rasmniel commented Jul 26, 2017

I am certainly not using an older version - I'm currently running 4.0.0-beta.14 as stated above.
I can get it to print out a FOCUS event using this code with the Router's createReducer prop:

const reducerCreate = (params) => {
    const defaultReducer = new Reducer();
    return (state, action) => {
        console.warn('Action', action); // <-- this line prints the desired events!
        return defaultReducer(state, action);
    };
};

... or by just putting my own reducer directly into a function and returning it to the createReducer prop.

const reducerCreate = (params) => {
    return routeReducer;
};

But I don't know where to go from here, since I'm using Redux and it's not apparent to me how I utilize the data when I don't have access to them from my Redux reducers. At this point I'm not using the connect function, which makes me think I'm going incorrectly about integrating with Redux. As you can see in my initial post I keep state persistent which is the point with the router too, but it looks like the scenes are on a different state with this configuration.

@aksonov
Copy link
Owner

aksonov commented Jul 26, 2017

@rasmniel Could you post link to sample repo with redux usage? I'm using MobX but will try to help if you provide the example. Probably I have to modify RNRF to work with external state provider.

@hellsan631
Copy link

hellsan631 commented Jul 27, 2017

I am also having issues and am currently not able to persist the router state because of this. Its not showing up in redux at all. It doesn't seem like the connect function connects the state of the router with the store.

@rasmniel
Copy link
Author

rasmniel commented Jul 27, 2017

@aksonov I have constructed a little react-native project to demonstrate the issue.

You will find that the router behaves exactly as described above.
I hope this is sufficient to assist you in fixing the issue, otherwise let me know.

Thanks for your effort!

@aksonov
Copy link
Owner

aksonov commented Jul 27, 2017

@hellsan631 RNRF v4 manages navigation state by itself, like v3 version did. I will think how to work with external state, it could be good enhancement.

@aksonov
Copy link
Owner

aksonov commented Jul 27, 2017

@rasmniel Thanks, will take a look

@hellsan631
Copy link

@aksonov how do you persist the router state when your application closes? My Idea for a work-around was to keep track of a state change on the router and during rehydration (loading of an existing state) I could navigate the router to the desired component, but it throws errors about setting state during a router transition.

@aksonov
Copy link
Owner

aksonov commented Jul 27, 2017

@hellsan631 It will work after this enhancement will be done.

@aksonov
Copy link
Owner

aksonov commented Jul 27, 2017

@rasmniel Your example is very helpful. One difficult thing to implement is creation of initial state - reducer must know it at compile time, but Router is created later, runtime. Any ideas how to avoid it?

@rasmniel
Copy link
Author

I am afraid I don't have the answer, but in regards to initializing state, I found this Redux library, which might contain some code that could serve as an inspiration: redux-async-initial-state

I'm guessing you will be able to create an initial state for the Router, which is then be injected into the Redux store as an enhancer, through the applyMiddelwareor compose functions, but this is where my knowledge about react-native ends, I reckon...

@aksonov
Copy link
Owner

aksonov commented Jul 28, 2017

Probably I will restore old v3 syntax Actions.create(<Scene>...</Scene>) to create all actions BEFORE Router usage for this. Does it sound good?

@aksonov aksonov changed the title Navigation events not firing through reducer. Support of external navigation state (full redux support) Jul 28, 2017
@rasmniel
Copy link
Author

I don't mind that syntax - so if it enables storing navigation state inside Redux without breaking new functionality, I say do it!

@aksonov
Copy link
Owner

aksonov commented Jul 28, 2017

@rasmniel Okey, please check https://github.com/aksonov/rnrfSample

@aksonov
Copy link
Owner

aksonov commented Jul 30, 2017

Check latest master now.

@rasmniel
Copy link
Author

There you go! This works as expected, and events are now firing properly within Redux.
You can safely push the changes to the next release, imo 👍
Thanks for the solution! :)

@jordenchang55
Copy link

The example works well, but when I try to use immutable with redux, it shows cannot update during an existing state transition warning. Here is the screen shot and my fork from rnrfSample.
Tried the solution of #2063 but not work.
simulator screen shot 2017 9 23 9 22 31

@willymulyana
Copy link

willymulyana commented Oct 6, 2017

I tried the sample project and it works fine, really need RNRF + Redux.

Still not actually use it in my production, but by changing RNRF version from ^4.0.0-beta.21 to github:aksonov/react-native-router-flux#redux first thing I notice is the tabs Scene's child seem not read the icon prop (for styling purpose). So I guess the intended version of RNRF to work together with Redux is not sliced from ^4.0.0-beta.21 or maybe accidental coding that makes icon prop not working.

Actually I was trying to show header above tabs Scene to no avail. It's first time I use tabs in RNRF, not sure if can show header too in RNRF prior to 4. To achieve this, a stackoverflow direct me to use static header Component (placed as sibling to RNRF Router), it's easy, but the problem is, I need a Scene that isn't included in tabs to not show this static header. And that's the reason I need RNRF + Redux, to make the static header Component know which Scene is in focus and not rendered on certain Scene(s).

@willymulyana
Copy link

I think with https://github.com/aksonov/react-native-router-flux/issues/2151 I should stick with ^4.0.0-beta.21.

@willymulyana
Copy link

willymulyana commented Oct 7, 2017

I can make it works with ^4.0.0-beta.21, however to access current Scene I use routeReducer.routes[routeReducer.index].routeName, so not using Actions.currentScene as in the example as it show previous scene in focus. Not sure why it differ, but I can go on with current method.

@zlandau2
Copy link

@jordenchang55, did you happen to figure out a fix for the warning about not updating during a render?

@jordenchang55
Copy link

@zlandau2, Sorry for my poor English. What do you mean figure for a fix?

@aksonov
Copy link
Owner

aksonov commented Nov 27, 2017 via email

@RadiksMan
Copy link

RadiksMan commented Nov 27, 2017

Update all, but the error still remains (
http://joxi.ru/EA46PPyuw7z5em

@kajm
Copy link

kajm commented Dec 6, 2017

@RadiksMan have you solved it?

@RadiksMan
Copy link

@kajm No

@kajm
Copy link

kajm commented Dec 6, 2017

@aksonov I did the smallest possible example from your example (https://github.com/aksonov/rnrfSample) and i got this error. What do you think cause this error?

img_1345

@antonsivogrivov
Copy link

@kajm same here

@digitaldavenyc
Copy link

I'm having a different issue, I followed the example almost exactly and getting this error:

img_2153

My libraries are:

"redux": "3.6.0",
"react-redux": "5.0.4",
"react": "16.2.0",
"react-native": "0.51.0",
"react-native-router-flux": "^4.0.0-beta.24",

containers/main.js

const ReduxRouter = connect((state) => ({ state: state.route }))(Router);
import reducers from '../reducers';

let _this;

const navigator = Actions.create(
	<Stack key="root" hideNavBar={true}>
		<Scene key="init" component={Init} hideNavBar={true} duration={0} initial={true} />
		<Scene key="onboard" component={Tutorial} hideNavBar={true} duration={0} />
		<Scene key="authenticate" hideNavBar={true} component={Authenticate} />
		<Scene key="signin" component={SignIn} hideNavBar={true} duration={250} />
	</Stack>
)

export default class groovemaps extends Component {
	render() {
		return (
			<Provider store={createStore(reducers, {})}>
				<ReduxRouter navigator={navigator} />
			</Provider>
		);
	}
}

reducers/router.js

import {Reducer, ActionConst, Actions} from 'react-native-router-flux'

const defaultReducer = Reducer();

export default (state, action) => {
	console.log('Reducing action: ', action.type);
	switch (action.type) {
		case ActionConst.FOCUS:
			console.log('FOCUS event fired with scene parameter: ', action.routeName);
			return defaultReducer(state, action);

		default:
			return defaultReducer(state, action);
	}
}

reducers/index.js

import { combineReducers } from 'redux';
import router from './router';
import user from './user';
import settings from './settings';

export default combineReducers({
  router,
  user,
  settings
});

@code-freakz
Copy link

@digitaldavenyc
try "import reducers from '../reducers';" after actions.create

@gsulloa
Copy link

gsulloa commented Jan 11, 2018

@kajm same here.
The only way I can avoid it, is not giving the state. But when I do it, the navigation state is not in my redux store.
Any solution or idea to solve it?

@kajm
Copy link

kajm commented Jan 12, 2018

@gsulloa i actually ended up with react-native-navigation by wix instead. Works good in my opinion.

@fatfatson
Copy link

will github:aksonov/react-native-router-flux#redux be merged back to master?
@aksonov

@aksonov
Copy link
Owner

aksonov commented Jan 26, 2018

No, it is not related to this topic. Check forked redux sample https://github.com/aksonov/rnrfSample

@fatfatson
Copy link

@code-freakz import sentence will be auto moved to the top of file, use require instead.

@fatfatson
Copy link

@aksonov yes I have downloaded that sample and ran it ok, but it has to be configuared depending on the special branch instead of latest mater, so I ask if(when) that branch will be merged back.

@aksonov
Copy link
Owner

aksonov commented Jan 26, 2018

No, it should work with latest master, please check

@fatfatson
Copy link

image
@aksonov get this error after replacing the RNRF to either npm latest or git master

@YangYouYong
Copy link

@fatfatson I get the same error

@aksonov
Copy link
Owner

aksonov commented Jan 26, 2018

Need to adopt latest version then... It worked before

@digitaldavenyc
Copy link

@code-freakz I tried that and I still get the undefined property error on Object.getStateForAction

@digitaldavenyc
Copy link

@aksonov Are you sure the code sample will work with the latest on master?

@marciobueno1
Copy link

@aksonov Your sample works until 4.0.0-beta.23.

On version 4.0.0-beta.24 and later it gives the error shown on fatfatson comment.

@aksonov
Copy link
Owner

aksonov commented Jan 29, 2018

Yes, then deep linking is the reason... I don't know how deep linking should work for external state yet. PR is welcome.

@prudhvir3ddy
Copy link

@digitaldavenyc did you find anything ? iam getting the same error . please help me

@digitaldavenyc
Copy link

@prudhvir3ddy I am sorry but I have had to deprecate our integration with RNRF and Redux. It's creating a fairly serious problem for us and may have to just engineer an undesirable solution.

@prudhvir3ddy
Copy link

@digitaldavenyc 3.43.0 is working good with latest RN you can try that

@digitaldavenyc
Copy link

@prudhvir3ddy We have spent a lot of time converting to RN 4.0 Beta, downgrading isn't really an option for us at this point.

@antoantonyk
Copy link

antoantonyk commented Jul 15, 2018

if any one knew which version working correctly? i tried beta 23,25,27 and 31 sadly nothing seems working, Please help

@abhigupta92
Copy link

abhigupta92 commented Dec 17, 2018

Hi, I am using following configuration for my project :

react : 16.6.3
react-native : 0.57.4
react-native-router-flux: 4.0.6

So I am trying to integrate redux with my scenes.

My Scene Component

class Login extends Component {

  const mapDispatchToProps = dispatch => {
    return {
      otpSend: () => dispatch(otpSend())
    };
  };

  const mapStateToProps = state => {
    return {
      routes: state.routes,
      otp: state.login.otp
    };
  };

  export default connect(
    mapStateToProps,
    mapDispatchToProps
  )(Login);
}

My App.js Class ( Starting Class )

import Routes from "./src/screens/routes";

const store = configureStore();

export default class App extends Component {
  render() {
    return (
      <Provider store={store}>
        <Routes />
      </Provider>
    );
  }
}

My Routes Class :

class Routes extends React.Component {`
  reducerCreate(params) {`
    const defaultReducer = Reducer(params);`
    return (state, action) => {`
      this.props.dispatch(action);`
      return defaultReducer(state, action);`
    };`
  }`

  render() {
    return (
      <Router createReducer={this.reducerCreate.bind(this)}>
        <Scene key="root">
          <Scene key="landing" component={Landing} title="Landing" initial />
          <Scene
            key="login"
            component={Login}
            title="Login"
            type="reset"
          />
        </Scene>
      </Router>
    );
   }
}

export default connect()(Routes);

So my otpSend dispatch method is triggered as expected.

What doesn't work : My props are not getting updated in my Login Scene Component.

The componentDidUpdate method is not triggered.

I am not sure what I am missing or if it is not supported at all by RNRF. Could someone please help me out here 🙏

Update : I got it to work.. Just upgraded libraries and it started to work :|

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests