I've fletched a list of items and rendered it into my app.
Its the first page of the app.
The thing that I want to do is:
Make each of the items "touchable", and when you touch it, you open a component filled with objects from a second fetch requisition.
I am new to react native, do you know if I have to use a lib or something to do it?
I'll try to answer your questions one by one.
Make each of the items "touchable"
Wrap your components with TouchableOpacity which you can import from react native like this import {TouchableOpacity} from "react-native";
when you touch it, you open a component filled with objects
You need to implement onPress method there and also react navigation to load other components.
<TouchableOpacity onPress={() => this.props.navigation.navigate("newScreenName")}>
<MyCustomComponent>
...
</MyCustomComponent>
</TouchableOpacity>
and creating screen will be like this :
import { createStackNavigator } from "react-navigation";
import Screen1 from "./Screen1";
import Screen2 from "./Screen2";
...
const customStackNavigator = createStackNavigator(
{
newScreenName: {
screen: Screen1
},
newScreenName1: {
screen: Screen2
}
},
{}
);
check API & Docs here
Also, Please check this example for more details
Related
I'm trying to set up an interactive "map" using react but I don't see how to set it up.
my interactive map is an aerial image of a place on which I would like to add hotspots that display a preview of the place with another image.
Afterwards if I click on a preview I would like to display the image in real size but I don't see how to do it...
I use React
I am open to any advice and any proposal!
thank you all
Look into Leaflet https://leafletjs.com/reference-1.6.0.html, it has npm packages that integrate it with react https://react-leaflet.js.org/.
Leaflet allows you to display a map and create custom HTML based Marker components. These markers can listen to user interaction events such as onClick and onMouseOver. On catching a user click or hover event, you can render whatever you need on top of the marker - such as your image, maybe with a nice title, description or whatever else you might need.
On clicking the image, you might want to display the image with different CSS styles in another view, so that you can display it in full width and height, or you might even setup a link to the original image URL, which would be much simpler, but at the same time it would drive users temporarily out of your site.
import React from 'react'
import { divIcon } from 'leaflet'
import { Marker } from 'react-leaflet'
import { renderToStaticMarkup } from 'react-dom/server'
import PropTypes from 'proptypes'
import 'leaflet/dist/leaflet.css'
const Index = props => {
const iconMarkup = renderToStaticMarkup(
<i
className="dispatcher-marker fa fa-map-marker-alt"
style={{ color: props.location.color }}
/>
)
const customMarkerIcon = divIcon({
html: iconMarkup
})
return (
<Marker
position={[ props.location.lat, props.location.lng ]}
icon={customMarkerIcon}
opacity={props.opacity}
onClick={() => props.handleClick(props.location.id, props.route)}
/>
)
}
Index.propTypes = {
handleClick: PropTypes.func,
location: PropTypes.object.isRequired,
route: PropTypes.object.isRequired,
opacity: PropTypes.number.isRequired,
}
export default Index
I tried to display MathML equation in my react native app using MathJax, but it is not showing. In the code below, the equation is not displayed, only "Helloworld".
import React, {Component} from 'react';
import {Text, View} from 'react-native';
import MathJax from 'react-native-mathjax'
export default class TipsAndTricksScreen extends Component {
static navigationOptions = {
title: 'Tips And Tricks',
};
render() {
return (
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<MathJax math={String.raw`<math xmlns="http://www.w3.org/1998/Math/MathML"><msqrt><mn>2</mn><mfrac bevelled="true"><mn>7</mn><mn>7</mn></mfrac></msqrt><mo>+</mo><mfrac><mn>5</mn><mn>8</mn></mfrac></math>this is just a string`} />
<Text>Helloworld</Text>
</View>
);
}
}
It seems quite straight forward to implement the dependency. Looking at the source code of the dependency it looks like it is just a wrapper around a Webview, so just be aware that it will probably only work if you are online.
The dependency has some default options already set for MathJax and you can pass further options using the mathJaxOptions prop. So if we pass
{
jax: ['input/MathML']
}
then it should tell MathJax that you are passing MathML as a input.
So here is a simple component that uses react-native-mathjax
import React, { Component } from 'react';
import { View, Text } from 'react-native';
import MathJax from 'react-native-mathjax';
const mmlOptions = {
jax: ['input/MathML'],
};
class MathView extends Component {
render () {
return (
<View style={{flex:1}}>
<MathJax
mathJaxOptions={mmlOptions}
html={'<math xmlns="http://www.w3.org/1998/Math/MathML"><msqrt><mn>2</mn><mfrac bevelled="true"><mn>4</mn><mn>7</mn></mfrac></msqrt><mo>+</mo><mfrac><mn>5</mn><mn>8</mn></mfrac></math> this is just a string'}
/>
</View>
);
}
}
export default MathView;
This would give you something like this
That should be enough to get you started. You can pass additional options via the mathJaxOptions prop. You just need to look at the MathJax documentation for all the different things that you can pass.
Caveat
On Android it doesn't look like the Android WebView can render MathML, there maybe a configuration that will make it work but I don't know it, however the Android WebView does render LaTex, so perhaps converting your MathML to LaTex could be a fallback option for you.
If you want to render MathML in React Native, you'll need some extensions and of course input and output method. After some research, I found this solution particular for MML to HTML:
<MathJax
html={`<math xmlns="http://www.w3.org/1998/Math/MathML"><msqrt><mn>2</mn><mfrac bevelled="true"><mn>7</mn><mn>7</mn></mfrac></msqrt><mo>+</mo><mfrac><mn>5</mn><mn>8</mn></mfrac></math>this is just a string`}
mathJaxOptions={{messageStyle: 'none',
extensions:
['mml2jax.js','MathMenu.js','MathZoom.js','AssistiveMML.js','a11y/accessibility-
menu.js',],
jax: ['input/MathML', 'output/CommonHTML'],
tex2jax: {
inlineMath: [['$', '$'], ['\\(', '\\)']],
displayMath: [['$$', '$$'], ['\\[', '\\]']],
processEscapes: true,},
TeX: {extensions:['AMSmath.js','AMSsymbols.js','noErrors.js','noUndefined.js'],},}} />
I'm new to react-navigation and trying to wrap my head around how to do the following:
Given this navigation structure:
RootTabNavigator
LoggedOut_StackNavigator
...
LoggedIn_StackNavigator
LoggedIn_TabNavigator <-- TabBar rendered by this Navigator
TabA_StackNavigator
ScreenA
ScreenB
I would like to be able to navigate from ScreenA to ScreenB using the typical "slide in from right" transition, in such a way that the TabBar is visible on ScreenA, but is not visible on ScreenB. In other words, when I navigate to ScreenB, I want it to take up the entire window.
Once the user transitions from ScreenA to ScreenB, they can either press the back button to return back to ScreenA, or navigate to new routes using the same transition with the TabBar still not visible.
What I've tried:
navigationOptions.tabBarVisible: this property only seems to work when applied to TabA_StackNavigator itself, which means that all of the screens in its stack also conceal the TabBar. Adding it to the screens inside the StackNavigator has no effect.
Adding a new AllScreens_StackNavigator as a sibling of LoggedIn_TabNavigator and navigating to routes inside this navigator, I get the error: Expect nav state to have routes and index, {"routeName":"ScreenB", "params": {}, "key": "init-id-1516..."}. The navigation action I dispatched to try to do this:
{
"action": Object {
"params": Object {},
"routeName": "ScreenB",
"type": "Navigation/NAVIGATE",
},
"params": Object {},
"routeName": "AllScreens_StackNavigator",
"type": "Navigation/NAVIGATE",
}
Any help is greatly appreciated!
Edit: this answer is relevant to react-nagivation v1.~ (pre v2.0)
As suggested in the comments, see this issue:
https://github.com/react-navigation/react-navigation-tabs/issues/19
Apparently, the navigationOptions of an inner component affect the containing navigator's parent navigator as well.
Solution
That means this code should work for you:
class ScreenB extends React.Component {
static navigationOptions = {
header: () => null, //this will hide the Stack navigator's header (TabA_StackNavigator)
tabBarVisible: false //this will hide the TabBar navigator's header (LoggedIn_TabNavigator)
}
Explanation
First, you can set the navigation options per individual screen (component). You can see how in the code snippet above or here: React Navigation - Screen Navigation Options
Second, you tried:
Adding it to the screens inside the StackNavigator has no effect.
It didn't work because hiding the StackNavigator's header requires setting the header field to null.
From the React Navigation documentation:
React Element or a function that given HeaderProps returns a React
Element, to display as a header. Setting to null hides header
Third, using tabBarVisible is actually correct, but it affects only the TabNavigator. And to make it disappear only for one tab and not for all the tabs, you need to set it on the specific screen. ScreenB in your case.
Hope this helps!
The following is what ended up working for me, so I'm posting it the hopes that it helps others. I haven't had a chance to try #talzaj's implementation so I'll leave it up to others to upvote whatever works best for them. The following solution has been working well for me, including inside nested navigators.
I updated my navigation structure such that:
LoggedIn_StackNavigator still has LoggedIn_TabNavigator as one of its screens, and this LoggedIn_TabNavigator is the initial route of LoggedIn_StackNavigator as set using initialRouteName.
LoggedIn_StackNavigator also contains a route for every screen that will ever need to be shown full screen and conceal the tab bar. (If you are re-using screens, where some are shown with the tab bar visible and others where it is not, make sure to use unique keys for routes that re-use the same screen.
Navigation Structure
So, the navigation structure looks like:
RootTabNavigator
LoggedOut_StackNavigator
LoggedIn_StackNavigator
ScreenA // ( reuse screen component, different route key )
ScreenB // ( reuse screen component, different route key )
LoggedIn_TabNavigator <-- TabBar rendered by this Navigator
TabA_StackNavigator
ScreenA
ScreenB
LoggedIn_StackNavigator:
And LoggedIn_StackNavigator looks like:
import { StackNavigator } from 'react-navigation';
import LoggedIn_TabNavigator from './LoggedIn_TabNavigator';
import {
ScreenA,
ScreenB,
} from './LoggedIn_TabNavigator/TabA_StackNavigator/Screens';
const LoggedIn_StackNavigator = StackNavigator({
WithoutTabBar_ScreenA: {
screen: ScreenA
},
WithoutTabBar_ScreenB: {
screen: ScreenB
},
LoggedIn_TabNavigator: {
screen: LoggedIn_TabNavigator
}
}, {
initialRouteName: 'LoggedIn_TabNavigator'
});
export default LoggedIn_StackNavigator;
From there, I wrote a helper HOC for pushing full screen routes:
import React from 'react';
import { withNavigation } from 'react-navigation';
import { fullScreenRoutePrefix } from './somewhere';
export default function withNavigateFullScreen(Child) {
#withNavigation
class WithNavigateFullScreenHOC extends React.Component {
navigateToFullScreenRoute = (routeName, params) => {
this.props.navigation.navigate(
`${fullScreenRoutePrefix}${routeName}`, params
);
}
render() {
return (
<Child
{...this.props}
navigateFullScreen={this.navigateToFullScreenRoute}
/>
);
}
}
return WithNavigateFullScreenHOC;
}
And then I can navigate to full screen routes like so:
import React from 'react';
import { withNavigateFullScreen } from 'components/higher-order';
import { Text } from 'react-native';
#withNavigateFullScreen
export default class ScreenA extends React.Component {
goToScreenB = () => {
this.props.navigateFullScreen('ScreenB');
}
render() {
return <Text onPress={this.goToScreenB}>Go To Screen B</Text>;
}
}
I'm using React Native which ships with React 16 alpha release which supports portals. While in browser and having access to DOM we can use id or classes to access element from anywhere in component/file hierarchy like this:
const modalRoot = document.getElementById('modal-root');
and pass it to createPortal(child, container) container arg. React docs clearly says than container should be DOM element:
The second argument (container) is a DOM element.
This function is also a method of ReactDOM which doesn't exist in React Native.
Is there a way to achieve the similar functionality in React Native?
Use case:
I want to render an animated overlay in the root of my application but pass the Animated values props to it from a parent deep in the tree hierarchy (can't use Redux actions for such things).
I had similar problem where I wanted to render overlay on top of everything from deeply nested child component. I solved my problem with React Native's Modal
It renders its content on top of everything :) Easy to use and no need for extra dependencies
I don't think react-native provides this functionality in its own API.
But there is a library available which provides the similar functionality. react-gateway
As per the docs of react-gateway,
It also works in universal (isomorphic) React applications without any additional setup and in React Native applications.
React Gateway does not directly depend on react-dom, so it works fine with React Native under one condition:
You must pass React Native component like View or similar to component prop of .
import React from 'react';
import { Text, View } from 'react-native';
import {
Gateway,
GatewayDest,
GatewayProvider
} from 'react-gateway';
export default class Application extends React.Component {
render() {
return (
<GatewayProvider>
<View>
<Text>React Gateway Native Example</Text>
<View>
<Gateway into="one">
<Text>Text rendered elsewhere</Text>
</Gateway>
</View>
<GatewayDest name="one" component={View} />
</View>
</GatewayProvider>
);
}
}
The above example is taken from the repo itself. react native example
One way to render the items above the screen can be done using react-native-paper library.
import * as React from 'react';
import { Text } from 'react-native';
import { Portal } from 'react-native-paper';
const MyComponent = () => (
<Portal.Host>
<Text>Content of the app</Text>
</Portal.Host>
);
export default MyComponent;
Portal host renders all of its children Portal elements. For example, you can wrap a screen in Portal.Host to render items above the screen.
Here is the link which describes its usage:
https://callstack.github.io/react-native-paper/portal-host.html
My App.js file was getting very large, so I decided to move out all my classes to their own separate file, and this is what remains in my App.js
import React from 'react';
import {
AppRegistry,
Text,
View,
Button,
Image
} from 'react-native';
import { StackNavigator } from 'react-navigation';
import { TabNavigator } from 'react-navigation';
//screen imports
import RecentChatScreen from './RecentChatScreen';
import AllContactsScreen from './AllContactsScreen';
import ChatScreen from './ChatScreen';
import HomeScreen from './HomeScreen';
import InfoScreen from './InfoScreen';
const MainScreenNavigator = TabNavigator({
Home: { screen: HomeScreen },
Recent: { screen: RecentChatsScreen },
All: { screen: AllContactsScreen },
});
const NavTest = StackNavigator({
Home: { screen: MainScreenNavigator },
Chat: { screen: ChatScreen },
Info: { screen: InfoScreen }
});
I think that looks fine.
However in some of the class files, I need to reference those other screens in button events, like this:
onPress={ () => navigate('Home')}
This worked fine before when everything was in App.js, but how would I reference these screens(Home, Chat, Info, Recent, All) now in the their separate files when the definitions are in App.js?
Thanks!
You can export them in App.js:
// App.js
// ...
export {
MainScreenNavigator,
NavTest,
}
And then import them from it:
import {MainScreenNavigator, NavTest} from './path/to/App.js';
If your intent is just to navigate to the different screens, and not use any properties defined within a particular screens class, then you would not need to import anything. When you define the StackNavigator and lets say you are passing in that value into the AppRegistry as the entry point of the application. In your case, it could be something like this:
AppRegistry.registerComponent('NavTest', () => NavTest)
Now within any of the screens, the navigatation object is passed in as a prop. You can then use that to navigate to any of the defined screens. The initial setup of the StackNavigator is essentially a mapping from a routeName to a react component (a class). So when you want to navigate to a particular class, all you need is the name of the route not the class or component it represents, the navigator already has all that. This name would be the key passed into the StackNavigator for a particular screen. In your example, the routeNames are Home, Chat and Info. So just doing something like this would work:
const { navigate } = this.props.navigation;
return (
<View>
<Text>Navigate Test</Text>
<Button onPress={() => navigate('Chat')} title="Go to chat"/>
</View>
);