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

React Native #743

Closed
ryanflorence opened this issue Jan 31, 2015 · 95 comments
Closed

React Native #743

ryanflorence opened this issue Jan 31, 2015 · 95 comments

Comments

@ryanflorence
Copy link
Member

Just tracking react native thoughts here. My assumptions are probably all wrong since 1) I don't know much about native dev and 2) I've spent 5 minutes with react native but:

  1. Looks like a component is mounted as the "top level" thing, the router listens to a location and then renders an app, so the basic usage is probably going to be slightly different, your top level component has route definitions and gets a url passed in as a prop or something.
  2. We need some sort of iOS Location and eventually an Android location, it'll probably be stored in memory and persisted to some sort of localStorage equivalent. When the app boots we look at the URI requesting the launch first, and then the localStorage (whatever it really is) second.

Again, I have no idea what I'm talking about yet. ¯(º_o)/¯

@petehunt
Copy link
Contributor

There will be a localStorage with the same API as the regular one except async

@petehunt
Copy link
Contributor

Possibly of interest: http://applinks.org/

@mjackson
Copy link
Member

I'd prefer to have a synchronous way to store URLs, just because all our transitions are sync by default.

@rpflorence Ideally we would be able to render the top-level component and not have to embed the router in some other component, no?

@ryanflorence
Copy link
Member Author

I'm just making wild guesses, but every app has Bundler.registerComponent('MoviesApp', () => MoviesApp); which appears to be rendered automatically.

@appsforartists
Copy link

The components would have to be different too. You don't have a DOM <a>, so <Link> needs to reimplement it.

@gaearon
Copy link
Contributor

gaearon commented Feb 5, 2015

Strictly I wouldn't say <Link> is beneficial in React Native. I rarely see iOS interfaces using links.
Most of the times I assume you'd just use transitionTo and friends.

@appsforartists
Copy link

Perhaps, though, links are the navigation paradigm on the web (not just for text). As part of "Learn Once, Write Everywhere," there's a strong case to be made for maintaining a declarative way to create transitions (even if they don't default to blue text).

For instance, I think this should work with react-native:

<Link to = "home">
  <Image source =  { ix("logo.svg") } />
</Link>

@gaearon
Copy link
Contributor

gaearon commented Feb 5, 2015

Yes, I suppose you're right.
I wonder how having different targets (like Web and React Native) would work for a library.

@appsforartists
Copy link

The naive solution would be something like this:

try {
  var React = require("react/addons");
} catch (error) {
  if (!error.message.includes("Cannot find"))
    throw error;

  var React = require("react-native/addons");
}

and then choose a "div" or a View depending on what's available. It would be nice if they made this easier in the standard library though.

I came really close to submitting a feature request to have DOM shims for the RN primitives (View, Text, and Image) added to React, but I backed down when I realized that's probably too close to "write once, run everywhere". For instance, img uses srcSet and Image uses source. I imagine reimplementing srcSet on top of Image is exactly the kind of maintenance hell they are trying to avoid by discouraging component reuse across platforms.

@agundermann
Copy link
Contributor

Perhaps branch via process.env in some way? Webpack and browserify users could remove dead code, and library authors could offer pre-bundled versions for each target (require('library/android')). Default could be web, or determining target at runtime.

@lwansbrough
Copy link

@appsforartists You're right, the goal of React Native is not to enable "write once" mentality, thus I think your example would be an anti-pattern. You should maintain different code bases for different platforms. But I do agree with you that Links should be available much like they are on the web. Views should be linkable. Otherwise I'd expect that it would be possible to route using regular JS from a click handler. (Not sure if this is already possible with React router - I'm assuming it is.)

@johanneslumpe
Copy link
Contributor

I know there hasn't been any major progress here yet, but I think it would be nice, if the router would be "smart" about where to transition to. If we have a navigation stack which already contains a, b and c, and we then want to transition to a, it would be nice if the router then popped b and c from the stack in order to get to a, instead of adding a new instance of a to the stack. This type of "infinite pushing" is a common mistake/error I have seen in iOS applications and if we could tackle that on the router level, that would be pretty nice I think.

edit: Since there actually is already a Navigator component available, which is being used to navigate between scenes and to determine which scene to render initially etc., the router could probably somehow leverage that under the hood?

@ryanflorence
Copy link
Member Author

we're working on this, don't think we need the issue anymore.

@danscan
Copy link

danscan commented Jun 30, 2015

Any update on this? React Router on RN would be HUGE.

@VonD
Copy link

VonD commented Jul 5, 2015

+1

@brentvatne
Copy link

ping @ryanflorence - curious to hear how this is coming along and if there is anything that we can do to help! I see the most recent commit on the react-native branch was about 21 days ago: bf6f9a7 - if you could put up a checklist for remaining tasks perhaps a few of us could try to tackle them

@lwansbrough
Copy link

I too would like to know. I see there's a branch here: https://github.com/rackt/react-router/tree/react-native

Do you guys have an estimate for the completion of this? Would you like help?

@danscan
Copy link

danscan commented Aug 15, 2015

Anybody...? It looks like the react-native branch has been deleted. I know support for react-native was being developed for history, but would love an update on where things stand for react-router.

@auser
Copy link

auser commented Aug 21, 2015

+1

1 similar comment
@simonexmachina
Copy link

+1

@esnunes
Copy link

esnunes commented Sep 15, 2015

Where can I find a sample of react-router + react-native?

@ippy04
Copy link

ippy04 commented Sep 21, 2015

👍

3 similar comments
@alexrecarey
Copy link

+1

@richarddewit
Copy link

+1

@keeth
Copy link

keeth commented Oct 13, 2015

👍

@joshhornby
Copy link

@ryanflorence Any update on this? Just about to start a big project in RN and would love to use React Router.

@taion
Copy link
Contributor

taion commented Nov 7, 2015

This isn't shippable in a reasonable way without the RN/React merge without something like #2031. And this issue is asking the wrong question anyway - the question is integration with Navigator, not some abstract support on its own.

cc @skevy

@skevy
Copy link

skevy commented Nov 7, 2015

Yah just a report on what I've been up to -

I have a working prototype of this in an app that's currently in beta at the moment. It's rough around the edges, but I think there's definitely going to be a way to make it work in a stable manner. Some of the harder parts around the integration is not actually developing a solution, but really figuring out the API around the right solution. Routing on the web does not map directly to routing on native. @ide talks about it a bit here: https://medium.com/the-exponent-log/routing-and-navigation-in-react-native-6b27bee39603.

The main issue is that a url of /app/me/profile doesn't give any information about the routes that came before it, which is something you need in a mobile app -- a concept of "implied" routes. In addition, most mobile apps have multiple navigators (each tab in a tabbed application usually has a nested navigator)...so the problem of how to deal with hierarchal history is an issue. There are multiple ways to solve the problem, but that's kind of the state of the world (as I'm aware) at the moment.

@taion
Copy link
Contributor

taion commented Dec 4, 2015

Do you think being explicit there is too tedious, though?

@skrigs
Copy link

skrigs commented Dec 5, 2015

I never like to have to specify something multiple times, but the route definition doesn't include all the information that might be required as a general solution. I think the library needs the ability to explicitly state the implied routes as you have indicated (even though it feels a bit tedious). In some circumstances it is possible that they could be derived and maybe there is some benefit in a utility library to calculate them for these use cases.

I'm in the process of building a solution for my app taking into account design suggestions from this conversation. I now have the ability to configure nested navigators as per a react-router hierarchy and with history. I can push new routes and everything renders correctly and also got the back navigation working with it also hooked up to the hardware button in android. I'm working with Redux so my solutions depends on that architecture so it isn't a good decoupled general solution. I have also allowed for the navigation bar to be specified on a NavigatorRoute as a custom component.

I'm not directly keeping the Navigator stacks and history in sync, but only update the Navigator stack via the Router which receives the current route via props. Interestingly the shape of the Navigator stacks don't match my history. e.g. if I visit Tab1->Tab2->Tab1 the navigator will only have two scene Tab1 & Tab2 and switch between them, however the history will include an entry for all three(3) so the android back has the right behaviour. By switching between the mounted components their states are maintained e.g. textinput.

My next task is to get implied routes working. At this stage I'm not sure how or where I'm going to store the implied routes for a given route. Possibly since I'm using Redux I will define them within action creators and accept params to interpolate each of the routes.

@skrigs
Copy link

skrigs commented Dec 5, 2015

I have decided to define the implied routes up front so on use I don't have to specify them. I have added a name property to all my routes (separate to path since I don't want params in their name) and then refer to them in an object as follows

const implied = {
   tab1:   ['base'],
   scene2: ['tab1',   '@tab1'],
   scene3: ['scene2', 'scene1', 'base']
}

A @ name (e.g. scene2) is an indicator to the implied generator to use another implied definition for the continued chain avoiding the need for duplication, however it can also be specified in full (e.g. scene3)

Now when doing a pushDeep I can refer to only the destination URL.Since I use redux I will generate the implied routes and interpolated them within a middle layer. The Router is then explicitly informed of the implied routes through a props update. In history I will hold the interpolated implied routes, otherwise I would have to hold the params.

Therefore having react native router expecting implied routes to be explicitly defined isn't really an issue.

@taion
Copy link
Contributor

taion commented Dec 5, 2015

Makes sense - ideally we can imply some of this from the route structure, but it's not going to be a core thing.

@jcgertig
Copy link

I implemented this kind of api as an example in react-native. Basically building a wrapper of the current Navigator api.

Looks like this

<Router platform="ios">
  <IndexRoute name="login" component={Login} />
  <Route name="home" component={Home} />
</Router>

https://github.com/jcgertig/rn-router

@tlvenn
Copy link

tlvenn commented Jan 1, 2016

@skrigs is there any chance you can open up your redux routing solution, I am kinda in the same boat as you and interested to see how you did it.

Generally speaking, with RN 0.18, RR 1.1 pretty much out of the door, is there a more concrete roadmap to have a routing solution based on the navigator for React Native ?

@pkieltyka
Copy link

hey all, I'm excited for RR to work with RN too, but until then here is a library my team wrote to help with routing - https://github.com/pressly/scene-router

@tlvenn
Copy link

tlvenn commented Jan 27, 2016

Btw the new navigator with animated being used under the hood that @skevy has mentioned is now available: https://github.com/ericvicenti/navigation-rfc

@taion
Copy link
Contributor

taion commented Jan 27, 2016

I'm not closing this issue just yet, but talking to @skevy, my current thinking is that this is a no-go.

  • Native routing may be nested, but it's not a general-case hierarchy; there are multiple levels, but the levels are in some sense special and not interchangeable – really in e.g. the iOS case it's a tab navigator with an embedded navigator per tab, rather than an arbitrary hierarchy of nested routes
  • In the general case,
  • The history paradigm is not appropriate for native navigation; we have history on the web side to shim around the browser APIs that we can't really control – the reducer-based paradigm from the repo above just makes a lot more sense when you can control all of history for yourself

Pending any compelling points to the contrary, I'm going to close this as a WONTFIX.

@taion
Copy link
Contributor

taion commented Jan 27, 2016

Also, the reducer-based paradigm gives much, much better integration with Redux than is possible with the current style of API.

Again, this isn't really possible on the web side because the ultimate source of truth is the browser rather than the history, but it's something to take advantage of for mobile.

@taion
Copy link
Contributor

taion commented Feb 13, 2016

Given the above, I'm going to close this issue for the time being.

@jmurzy
Copy link

jmurzy commented Sep 8, 2016

I know this thread is old, but I wanted to add another note for the benefit of people looking for a solution that makes React Router possible on React Native.

I've been making some exciting progress with react-router-native—a lib that marries React Router to NavigationExperimental.

For those of you who are interested, here's the pitch:

React Router community decided that a reducer-based paradigm similar to that of NavigationExperimental is better suited to native navigation. Transition to a reducer-based paradigm is also being discussed for the web. On the other hand, NavigationExperimental has no intention to support a React Router-like interface and leaves the navigation state up to the developer to maintain.

A declarative API removes the need to write boilerplate code and speeds up development. React Router Native follows React's Learn Once, Write Anywhere principle by providing a superset of React Router's API that marries React Router to NavigationExperimental.

Goals

  • URL Driven Development
  • Learn once, write anywhere: knowledge and proven idioms from react-router can be reused while extending them as necessary to allow navigation semantics unique to native platforms
  • First class deep linking support
  • Cross-platform

Please note that the address bar seen above is for development only and can be disabled by removing the addressBar prop from the <Router> component.

Feedback is greatly appreciated.

🍺

@taion
Copy link
Contributor

taion commented Sep 8, 2016

How do you model the case like on the Instagram and Facebook apps where you can hit the same scene from multiple tabs in the tab bar?

@jmurzy
Copy link

jmurzy commented Sep 8, 2016

@taion This is actually surprisingly easy to do:

const profileRoute = (
  <Route path="profile" component={Profile} overlayComponent={ProfileNavBar} />;
);

<Router history={nativeHistory}>
  <TabsRoute path="master" component={Master}>
    <StackRoute path="/tab1" component={Tab1}>
      <Route path="/home" component={Home} overlayComponent={HomeNavBar} />;
      {profileRoute}
    </StackRoute>
    <StackRoute path="/tab2" component={Tab2}>
      <Route path="/notifications" component={Notifications} overlayComponent={NotificationsNavBar} />;
      {profileRoute}
    </StackRoute>
  </TabsRoute>
</Router>

This is possible because we only use React Router to render the navigational components and delegate rendering of user components to NavigationExperimental. <Route>, <TabsRoute> and <StackRoute> all have stock reducers with sensible defaults associated with them that spit out navigation states that can then be fed into NavigationExperimental. So it is completely customizable per route via a custom reducer if you want to interpret a request completely independent of the browser behavior. That being said, I'm building a fairly complex app and the default reducers have been sufficient so far.

Hope this makes sense.

🍺

@taion
Copy link
Contributor

taion commented Sep 8, 2016

Right – that's where we ended up, but it didn't feel quite right. You can replicate a bag of routes/scenes across multiple tabs in this manner, but it feels like a worse way of handling configuration, and doesn't make a lot of sense to me from the perspective of the actual URLs.

Essentially, my dislike for an API that requires nesting the same {childRoutes} under multiple parent routes was the primary motivation for closing this issue in the first place.

@nikhildaga
Copy link

https://react-router-website-xvufzcovng.now.sh/MemoryRouter mentions that
MemoryRouter is useful in non-browser environments like React Native.

Does it mean we can use react router in react native apps from version 4?

@deevus
Copy link

deevus commented Sep 18, 2016

@nikhildaga Would also like to know what the status is. I get Expected a component class, got [object Object] when trying to use Link in RN

@deevus
Copy link

deevus commented Sep 18, 2016

The other components seem to work which is good, but I can't get a link to work

@angeloashmore
Copy link

angeloashmore commented Sep 18, 2016

You can create a custom Link component. Check out the code in React Router's Link to see how it works. The main reason it doesn't work out of the box is its usage of <a> rather than something like View or TouchableHighlight.

React Router works with React Native, but you won't get nice NavigationController-esque transitions without a lot of effort.

Edit: I haven't tried it with v4, only v3.

@karlmikko
Copy link

React-Router v4 will help with this issue https://medium.com/@jschloer/react-router-v4-with-react-native-5f2005ab2a72#.56mt46jj9 way to go @jschloer

@lock lock bot locked as resolved and limited conversation to collaborators Jan 21, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests