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

Comments

@ryanflorence
Contributor

ryanflorence commented Jan 31, 2015

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

This comment has been minimized.

Contributor

petehunt commented Jan 31, 2015

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

@petehunt

This comment has been minimized.

Contributor

petehunt commented Jan 31, 2015

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

@mjackson

This comment has been minimized.

Member

mjackson commented Jan 31, 2015

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

This comment has been minimized.

Contributor

ryanflorence commented Jan 31, 2015

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

@appsforartists

This comment has been minimized.

appsforartists commented Feb 5, 2015

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

@gaearon

This comment has been minimized.

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

This comment has been minimized.

appsforartists commented Feb 5, 2015

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

This comment has been minimized.

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

This comment has been minimized.

appsforartists commented Feb 5, 2015

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.

@taurose

This comment has been minimized.

Contributor

taurose commented Feb 6, 2015

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

This comment has been minimized.

lwansbrough commented Feb 15, 2015

@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

This comment has been minimized.

Contributor

johanneslumpe commented Apr 5, 2015

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

This comment has been minimized.

Contributor

ryanflorence commented Jun 16, 2015

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

@danscan

This comment has been minimized.

danscan commented Jun 30, 2015

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

@VonD

This comment has been minimized.

VonD commented Jul 5, 2015

+1

@brentvatne

This comment has been minimized.

brentvatne commented Jul 10, 2015

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

This comment has been minimized.

lwansbrough commented Aug 8, 2015

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

This comment has been minimized.

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

This comment has been minimized.

auser commented Aug 21, 2015

+1

1 similar comment
@aexmachina

This comment has been minimized.

aexmachina commented Aug 24, 2015

+1

@esnunes

This comment has been minimized.

esnunes commented Sep 15, 2015

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

@ippy04

This comment has been minimized.

ippy04 commented Sep 21, 2015

👍

3 similar comments
@alexrecarey

This comment has been minimized.

alexrecarey commented Sep 29, 2015

+1

@richarddewit

This comment has been minimized.

richarddewit commented Oct 6, 2015

+1

@keeth

This comment has been minimized.

keeth commented Oct 13, 2015

👍

@joshhornby

This comment has been minimized.

joshhornby commented Nov 7, 2015

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

@taion

This comment has been minimized.

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

This comment has been minimized.

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.

@skrigs

This comment has been minimized.

skrigs commented Dec 4, 2015

@taion you are correct anything else is inflexible. e.g. its possible that the routes in the stack have params in their URL that couldn't be derived from the route being visited at the top of the stack.

@taion

This comment has been minimized.

Contributor

taion commented Dec 4, 2015

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

@skrigs

This comment has been minimized.

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

This comment has been minimized.

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

This comment has been minimized.

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

This comment has been minimized.

jcgertig commented Dec 18, 2015

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

This comment has been minimized.

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

This comment has been minimized.

pkieltyka commented Jan 2, 2016

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

This comment has been minimized.

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

This comment has been minimized.

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

This comment has been minimized.

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

This comment has been minimized.

Contributor

taion commented Feb 13, 2016

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

@jmurzy

This comment has been minimized.

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

This comment has been minimized.

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

This comment has been minimized.

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

This comment has been minimized.

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

This comment has been minimized.

nikhildaga commented Sep 17, 2016

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

This comment has been minimized.

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

This comment has been minimized.

deevus commented Sep 18, 2016

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

@angeloashmore

This comment has been minimized.

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

This comment has been minimized.

karlmikko commented Sep 19, 2016

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