aksonov / react-native-router-flux

The first declarative React Native router
MIT License
8.99k stars 2.11k forks source link

[Discussion] v4 roadmap/desired features/etc #817

Closed aksonov closed 7 years ago

aksonov commented 8 years ago

I'm fan of autocomplete and type checking and want navigation with these features. Also i want to use navigation inside my business logic (react agnostic), not within views (however simple apps should be able to use actions from views). Persistence of nav state also could be nice. So I believe we need to split Actions creation into two different parts - navigation tree, actions API and view-specific data (render components, tabbars/navbars/etc).

Here is proposed syntax: User will define own actions:

import {scene, root, tabs, replace, NavigationStore} from 'react-native-router-flux';
class Actions extends NavigationStore {
  @scene(root) modal = [this.root, this.privacyPolicy, this.termsOfService];
  @scene(tabs) root = [this.launch, this.promo, this.logged];
  @scene privacyPolicy;
  @scene termsOfService;
  @scene promo;
  @scene logged = [this.home, this.friends];
  @scene launch;
  @scene home;
  @scene(replace) friends;
  @scene profileDetail(item: Profile) {}
}
export default new Actions();

profileDetail scene is analog of current 'clone' action - it doesn't belong to tree and can be pushed anywhere. Stacks are naturally defined as arrays. @scene will do some magic to transform all scenes into actions that modify navigationState :)

After that in App.js

import Actions from './Actions';
import {Scene, Router} from 'react-native-router-flux';
export default class App extends React.Component {
     render(){
          return <Router navigationState={Actions.navigationState} >
                   <Scene action={Actions.modal} component={Modal}/>
                   <Scene action={Actions.profileDetail} component={item => <ProfileDetails item={item} /> title={item=>item.displayName} />
                   <Scene action={Actions.launch} component={Launch} hideNavBar/>
                   <Scene action={Actions.login} component={Login} hideNavBar/>
                     // ... etc
          </Router>
     }
}

As you can see, there is no tree structure within React, only matching Action=>View All Scene has fixed propTypes (key, component, title, hideNavBar, hideTabBar, navBar, ..etc) - i.e. they don't contain specific component properties - all they are defined within component function in natural way, with autocomplete, strict type checking, etc.).

After that in your views you will still be able to use Actions.login() within your views. In my store i will be able to use Actions.login() as well (it will modify Actions.navigationState properly and re-render Router automatically - driven with MobX internally). About Redux - we could support it as we do it now or anything else you suggest. Redux may pass own navigationState to Router, the question how that navigationState will be modified by Actions...

cridenour commented 8 years ago

@aksonov This is very interesting. Since we are restricting the props in Scene to a defined set, will we still pass these props down to the component as well? Or is the thought that these are for the navigation stack and any important props should be passed in the action.

aksonov commented 8 years ago

@cridenour No, all props are passed to component and title functions, so it would be more correct:

<Scene action={Actions.profileDetail} initialState={{propA:'1231, propB:'12344'}} component={({item, propA, propB}) => <ProfileDetails item={item} propA={propA} propB={propB} />} title={({item})=>item.displayName} />

After some thinking i believe that Scene hierarchy is UI-specific (for example for Web it will be completely different. Not sure about initialState - should it be within React Scene or within action declarations.

aksonov commented 8 years ago

@cridenour Looks like i'm trying to invite bicycle to implement UI state model description. As I've found it is already standardized as SCXML format http://www.w3.org/TR/scxml/ - there is everything we need - states, transitions, guards at so on.

https://github.com/jbeard4/SCION converts it to pure JSON. So RNRF could just attach SCXML states to react native components.

cridenour commented 8 years ago

@aksonov Hm, while that is a W3 standard, how common is it? I'd like to hear some thoughts of others here - but I'm not sure adopting an unused standard would be beneficial.

aksonov commented 8 years ago

@cridenour It is approved recently (2015) and it looks great. It is not usual state machine, but pretty advanced. I've found SCXML GUI editor that works with SCXML nicely https://github.com/fmorbini/scxmlgui

Anyway, i've created Statem - Next-gen state management based on Harel Statechart and SCXML, migrated some part of my app and it works quite well.

Probably i would try to integrate Statem into current RNRF, without waiting for v4. I've just committed Statem support for Switch, so now you could use something like this:

<Router statem={statem}>
        <Scene key="root" component={Switch} tabs={true}>
          <Scene key="launch" component={Launch} default hideNavBar/>
          <Scene key="promo" component={Promo} state={statem.promoScene} hideNavBar/>
          <Scene key="signUp" component={SignUp} state={statem.signUpScene} hideNavBar/>
          <Scene key="logged" component={Drawer} state={statem.loggedScene} open={false} >
                 //...
          </Scene>
</Router>

Note, that Switch doesn't have selector. Once given scene application state will be active that scene will be rendered. Probably react-native-router-mobx is required to re-render Switch once state is changed.

chetstone commented 8 years ago

Apologies for not reading your proposal carefully enough to really understand it, but it sounds like a major API change and I wonder if it wouldn't be better to fork and create a new project? The V3 API seems to work OK for many users and it is still far from stable with breaking changes to NavigationExperimental still coming fast and furious. It seems to me to be confusing to have so many API's and changes happening all at once in the same repo.

On the other hand, if you think this new proposal is radically better and will provide enough improvement that a great majority of react-native-router-flux users will enthusiastically embrace it and be willing to change their code to use it, then maybe it's OK to do it here.

My two cents.

And by the way @aksonov thanks so much for your work.

tomprogers commented 8 years ago

I'd suggest that improving the documentation is a far more pressing concern than rerolling the semantics or adding new features. The featureset already on offer is unnecessarily difficult to leverage.

The existing docs are incomplete and would benefit from being reorganized. The in-depth example is poorly-annotated. Often the only way to discover the "correct" way to declare scene organization is by debugging the DefaultRenderer component.

Thorough, reference-grade documentation is especially needed for applyAnimation.

The icon prop of Scene should be renamed to something like renderTab, and its signature needs to be documented.

The list of action types emitted by RNRF must be enumerated, their payloads described, and the circumstances under which they're emitted must be explained. I'd also suggest namespacing the type values, because focus, push, and BackAction are reasonably likely to collide with app-specific business logic. Redux uses types like @@redux/INIT -- perhaps something like @@rnrf/PUSH, etc.

The Redux/Flux tutorial doesn't appear to show how to restore navigation state when the app boots. Apps that persist their redux store to disk (using AsyncStorage) will want to know how to do this. I would also welcome something that shows how to connect the Router to the Store using RNRF's ES7 decorator, @connect((state) => ({ /* ? */ })).

robclouth commented 8 years ago

Yeah, documentation would be brilliant. I know it's the boring bit, but it'll cut down on the number of issues submitted significantly. I would offer to help but I'm still figuring out the basics...