How to prerender a component in react-navigation before switching to it? - react-native

Inside my StackNavigator, one of the components includes web content with a long loading time. However, this screen will only be shown late in my navigation flow.
How can I use this time to render my component in the background before finally switching to it?
I couldn't find anything comparable to ReactDOM.render in React Native that would allow me to render it manually.

I am not aware of any option in react-navigation to preload a screen that is not displayed, except maybe when the screen is part of a tab navigator.
Depending on what is slowing down the rendering, you might be able to do some actions in the first screen and later pass the results to the second screen using a navigation parameter.
For instance, if you are fetching data from an api in the second screen, you could fetch this data in the first screen and pass it to the second one:
this.props.navigation.navigate('SecondScreen', { data: this.data });
If it is a component, you could also try to build it in the first screen and pass it in the same fashion:
this.props.navigation.navigate('SecondScreen', { component: this.component });
If you are rendering a WebView in the second screen, what can help is to render the WebView in the first screen too, but with no width or height. The WebView will not be displayed but the website data will be fetched and cached, making the real render more efficient:
render() {
return (
<View>
<WebView source={{ uri: 'https://github.com/facebook/react-native' }} style={{ height: 0, width: 0 }} />
{this.renderCurrentScreen()}
</View>
);
}

Related

display a view above a react nativigation modal

I have a custom snackbar component which has a zIndex higher than other views and an absolute position in the app.
The snackbar works fine, as long as no modals are opened. The problem is, I have nested navigation with nested modals and the snackbar component needs to be on top, all the time.
currently, my screenOptions are: { presentation: 'modal' }
Others like containedModal work, but gives me stacked headers for all the parent modals. I like the way modal presentation looks on iOs. Any ideas how an absolute View can be displayed above any modal from the root of the app?
Z-index in RN doesn't work the same as it does on web - see the docs for more. Components are rendered as a tree, with the first items on the bottom and stacking until the last items are on top.
Therefore you can put a component on top of everything else by rendering it outside and after everything else. I.e.
// App.js
const App = () => {
return (
<>
<NavigationContainer>
<MainStack />
</NavigationContainer>
<Snackbar />
</>
);
};

How to open all URL inside WebView not in external browser?

I am new to React native and I am trying to open my webpages(page1,page2) inside webview using react native, and my component's webview in the below example.
Here page1 contains button on clicking that button, page2 is opening in child window in external browser.
Can somebody please tell me how to open page2 inside the webview, so that the user can get a good experience?
Example: Component 1
{
<WebView
scalesPageToFit
startInLoadingState={true}
renderLoading={() => { return <Loading/> }}
**source={{uri:"url to page1"}}**
onShouldStartLoadWithRequest={request => {
return request.url.startsWith(domain);
}}
style={styles.web}
javaScriptEnabledAndroid={true}
javaScriptEnabled={true}
originWhitelist={[domain+"*"]}
/>
}
I found the below solution but was not able to implement it in my scenario.
https://github.com/facebook/react-native/pull/6886
I found the answer, this happened because of the latest react-native-webview version.
setSupportMultipleWindows={true} becomes true and in my case, it should be false.

Swipe to next screen (infinite)

I have a calendar section in my app where I want to be able to swipe right or left to go to the next or previous day.
I know that you can use createMaterialTopTabNavigator from React Navigation to do something similar, but I'm not sure if it would work in this specific scenario (where I would have an infinite number of screens and wouldn't be able to predefine them).
I also considered using react-native-gesture-handler's Swipeable component to navigate to the next/previous day screen on a left/right swipe but I'm not sure if this is the easiest/best way to approach this problem.
As you mentioned, you can use Tabs or Swipable. There are some other options like using <ifaram> or <WebView> and using a web URL instead of RN components but it's can be tricky and hard to manipulate.
As a simple solution, you can use carousels instead of using multi screen defining navigation. It's very simple. assume that your screens are an image in an image gallery and you can swipe left/right.
There are many libraries, one of the best ones is: react-native-snap-carousle
Take a look at it's example:
import Carousel from 'react-native-snap-carousel';
export class MyCarousel extends Component {
_renderItem = ({item, index}) => {
return (
<View style={styles.slide}>
<Text style={styles.title}>{ item.title }</Text>
</View>
);
}
render () {
return (
<Carousel
ref={(c) => { this._carousel = c; }}
data={this.state.entries}
renderItem={this._renderItem}
sliderWidth={sliderWidth}
itemWidth={itemWidth}
/>
);
}
}
So you can pass a screen/page as _renderItem to the Carousel

React native partial modal

I am working on a react-native app using react navigation.
I want to add a partial modal that covers 30% of screen when pressing on one of the tabs in the bottom-tab, similar to the "+" tab in the YouTube app:
Youtube modal
I've tried to use react-native Modal component, but
I have problems with activating it from bottom tab
it covers whole screen
Any suggestions?
Thanks..
To answer your question 100% correct I'd need to know more details about your project but, I can try to explain how can be your logic to do this withou any libs.
You can create another component called "Start" where you're gonna put your Modal with absolute position above your navigator.
You can create a Modal that will be above your navigator:
export const Start(){
return(
<View style={{flex:1}}>
<Modal>
<View/>
</Modal>
<NavigatorComponent/>
</View>
)
}
This is going to work because when you put a component with absolute position above the other, this component stay in front of the below component. In your case, will stay in front of everything including the TabBar.
To the modal has just 30% of the height you just need to put in its styles the attribute height: '30%'.
In the initial component of your App (usually the index.js file), you just return the new Start component.
I hope you like my answer. Please, if you have more questions you can ask. Waiting for your feedback :).

React Native - Interactive initial page

I'm interested in having a view which initially loads with my React Native app that essentially has nested components in it. These components will give visual queues to the user as to what state the app is in, eg: still loading data from the server, etc. Basically, it's not just a static splash screen. I might also add some kind of spinner/progress bar, eg: other animated components.
There are solutions out there for static splash screens that initially show while your app loads into memory, but I need to be able to load an initial component, and then remove it when the application's data is ready to go. Is there a convention/pattern to follow in order to achieve this? Is there a way to mount a component, then remove it when it's no longer necessary allowing the rest of the app to be displayed? What's a best practice for this using React Native?
This is what I used to do:
Use <Modal /> to provide your initial, interactive page. It will blocks the screen, with semi-transparent background; If you like it to be full width, just use flex: 1 within the <View /> inside <Modal />.
Use global object / queue for loading status information. My choice is rxjs, then your initial page can just listen to this one source of truth, suggest a BehaviorSubject. So you can subscribe on it for something like:
...
{ tag: 'FetchRemoteData', progress: 10 }
{ tag: 'LoadingComponent', progress: 5 }
{ tag: 'FetchRemoteData', progress: 20 }
...
Read it until match your "load complete" conditions, then close the model.
To make it clear with code.
app.js
render() {
return (
<View>
<InitialBlockingPage />
<YourMainApp />
</View>
);
}
initial-blocking-page.js
constructor(props) {
super(props);
this.state = {
visible: true
};
}
componentDidMount() {
globalQueue.subscribe( () => {
/// pseudo code: until fully loaded
if (fullloaded) this.setState({visible: false});
});
}
render() {
return (
<Modal visible={this.state.visible}>
<SplashScreenWithData />
</Modal>
);
}