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
Native global React context out of route #237
Comments
Use React Context to track your global values and then wrap a Context Provider around your exported export default ({crumb}) => (
<ThemeContext.Provider value="dark">
<NavigationHandler stateNavigator={stateNavigator}>
<Scene crumb={crumb} />
</NavigationHandler>
</ThemeContext.Provider>
); |
Hmm. I'm looking for something more like, export default ({ crumb }) => (
const [state, dispatch] = React.useDispatcher(…)
return (
<Context.Provider value={{ state, dispatch }}>
<NavigationHandler stateNavigator={stateNavigator}>
<Scene crumb={crumb} />
</NavigationHandler>
</Context.Provider>
)
) But importantly, we only initialise the reducer once. If I understand correctly, we re-initialize the app, so I'd lose the context. This might be less of an issue for people using Redux where there's a singleton store, but it'd be nice to use the native React APIs. |
That works. You don't need Redux but you do need a singleton outside of the component tree so that you can use the values across routes. // Global so it can be used across routes
var store = {};
export default ({ crumb }) => (
// Take the initial value from the global store
const [state, dispatch] = React.useReducer(…, { ...store } )
// Update the global store with the latest state
React.useEffect(() => {
store = { ...state };
});
return (
<Context.Provider value={{ state, dispatch }}>
<NavigationHandler stateNavigator={stateNavigator}>
<Scene crumb={crumb} />
</NavigationHandler>
</Context.Provider>
)
)``` |
I think that'll have a few issues with updating state across multiple routes. It was definitely possible to do this in the (now removed) NavigatorIOS. It might be possible to do it in this library, but you might find it out of scope, or there might be tradeofs. It internally mounted every route as a React child, and then used the But it had really odd logic to sync the JS and iOS view state, including setTimeouts. There were definitely bugs relating to animations and back gestures. But maybe your JS-driven only approach combined with their React children approach could be a neat solution |
The Navigation router uses this approach. It has a global |
When the state in one route updates, it’ll have to notify all other routes to update their states. But once you’ve done that you might as well just use redux |
But login data only updates once so you don't need any notifications |
It was just an example. I’m making a music app, and stuff like the current song, playlist etc is shared between routes |
I’ve got some ideas on what this might look like. I’ll try and find some time to play around with it in a new repo and paste it here. I reckon your render function in iOS combined with some of what they did in NavigatorIOS could work really well |
Cool, I look forward to seeing your ideas |
Why don't you like a Redux-like solution? |
Okay, I have a demo! https://github.com/jacobp100/NavigatorTest I wanted to go really React-like with this, so there's no imperative navigations. You just pass in the routes you wanna render, and it'll do it. <Navigator
style={{ flex: 1 }}
routes={routes}
onRoutesUpdated={onRoutesUpdated}
/> I know there's definitely some issues with the animations between routes - the titles seem to flash on mounting a route rather than slide in. But the back gesture is pretty smooth! |
Wow, thanks for that. It’s fascinating. So that’s how
I guess problems like these brought about the downfall of |
I haven’t thought about android too much — I’ve never actually done any native development with it. Is there advantages to using fragments over regular views and adding a toolbar? Failing that, I imagine I could just work out what pushes and pops are needed. Any tips would definitely be welcome here! There’s actually TabBarIOS in the React native core. This one is really solid, and already has access to the React tree Yeah there is a setState needed — I did onRoutesChanged. This bit needs a bit more work though, if they don’t call setState it should really push the old view back after the gesture (like how |
You should definitely keep going with your Navigator. I'm excited to see how it progresses. You should try getting it to work with Activities on Android. If you have trouble then take a look at the NavigationComponent The <Navigator routes={tab1routes} />
<Navigator routes={tab2routes} />
<Navigator routes={tab3routes} /> When you're implementing popping, try swiping back twice in quick succession. I think it will cause you problems because the native stack and JavaScript stack will be battling with each other |
Yeah, I'll definitely check out how you did Android!
Yeah, that's what I did before when NavigatorIOS existed. Also, some apps go the other way round, where the tab bar is in the route, because only some of the routes have tab bars (like Apple News) I know there will definitely be some race conditions over navigating. I guess in theory the JS could push a route while the user is doing the back gesture. Gotta think about this one! |
For clarity, the NavigationComponent isn't mine. It's part of Android. It's the in-built way to navigate with Fragments instead of Activities |
I’ve created a Redux example for React Native. It’s a master/details scenario where you can select a person from a list and edit their name. The |
👍 Still relies on Redux though 😉 One of the apps I'm rewriting in RN has some pretty crazy context providers that I wouldn't be ergonomic in Redux (web workers, input responder chain for math input fields, parent scroll view references etc.) The Blinkers stuff is neat! I had no idea you could do that, but that would have been really handy on one project I was on. Eventually we'll be able to de-prioritize parts of the tree in RN like |
I think you'd need Redux even if it was a single React tree because Context doesn't scale at the moment. React Redux had to back out their reliance on Consumers Not sure how deprioritzing parts of the tree would play with the swipe back. It's too expensive to trigger a You happy to close this issue? |
I'm reopening this. I ran into a problem implementing a search bar component that means can't add Changing to a single react root means loading views first and then navigating (instead of other way round with current approach). So should be able to get the search bar and add it in the The single root approach could address other problems:
There are things to worry about with single React root.
|
We do need some logic on the iOS side to wait for a back animation to complete before rendering the new routes. The real question is how this can be handled in the JS side — what’s the logical thing to do if you push a route onto a stack while a back animation is in progress? I have no idea if this approach works with Android. But this approach can be implemented purely in JS. What does doing this in the native android side give us? |
We can let the iOS back happen without doing a new render. iOS will remove the ViewControllers but we keep the subviews. There's no need to remove them. Then the views still match the React component tree. On the React side, each scene has their own Navigation context, so they're isolated from changes to the stack (from a scene's perspective, it always thinks it's at the top of the stack). We should use the platform for Android navigation, same as we do for iOS. Why implement the animations in JavaScript when Android already animates between Activities? Another example is shared elements. Android provides shared element transitions when starting a new Activity. It makes sense to use the shared element animations provided by the platform rather than implement our own. |
I meant there’s a case where a route is pushed based on some timeout, and they’re doing a back swipe at the same time a new route gets pushed. I’m not sure there’s a straightforward way to reconcile that Ah last I used android was Jelly Bean. Guess stuff has moved on a long way since. Pretty sure back then there was never an animation for that kind of stuff. I’ll probably have to spend some time doing native android dev at some point |
If I have some global context I want to apply to all routes (login data etc.), what's the best way to do this?
The text was updated successfully, but these errors were encountered: