I have a context that contains an array, this context has a function that updates a certain value in that array:
import React, { createContext, useState } from 'react'
export const SliderValueContext = createContext()
export function SliderValueProvider({ children }) {
const [intensity, setIntensity] = useState([
{
EXAMPLE0: 0,
},
{
EXAMPLE1: 0,
},
{
EXAMPLE2: 0,
},
])
const updateCertainIntensity = (value, index) => {
console.log('Index: ' + index)
console.log('Value: ' + value)
let newIntensity = [...intensity]
newIntensity[index] = value
setIntensity(newIntensity)
}
return (
<SliderValueContext.Provider
value={{intensity, updateCertainIntensity}}>
{children}
</SliderValueContext.Provider>
)
}
I have a basic StackNavigator with both of my screens:
import React from 'react'
import { createStackNavigator } from '#react-navigation/stack'
import Index from './index'
import SliderScreen from './screen'
const Stack = createStackNavigator()
export default function MyStack() {
return (
<Stack.Navigator>
<Stack.Screen name='Index' component={Index}/>
<Stack.Screen name='SliderScreen' component={SliderScreen}/>
</Stack.Navigator>
)
}
This is how my index looks like:
import React from 'react'
import {
Button
} from 'react-native'
import { useNavigation } from '#react-navigation/native'
import { SliderValueProvider } from './context'
export default function Index() {
const navigation = useNavigation()
return (
<SliderValueProvider>
<Button title='YOU' onPress={() => navigation.navigate('SliderScreen')}></Button>
</SliderValueProvider>
)
}
App.js
export default function App() {
return (
<NavigationContainer>
<MyStack>
</MyStack>
</NavigationContainer>
)
}
Custom Slider component:
export default function SliderGroup({ id, text, borderColor }) {
const { updateCertainIntensity } = useContext(SliderValueContext)
return (
<View style={[styles.slider_container, { borderColor: borderColor }]}>
<View style={styles.slider_container_text}>
<Text style={styles.text_style}> {text} </Text>
{/* <Text style={styles.number_style}> </Text> */}
</View>
<View style={styles.slider_container_slider}>
<Slider
onValueChange={(value) => updateCertainIntensity(value, id)}
step={1}
minimumValue={0}
maximumValue={5}
maximumTrackTintColor='rgb(255, 255, 255)'
/>
</View>
</View>
)
}
Problem: Whenever I try to access the useContext in my custom Slider component, it says that the context is undefined undefined is not an object (evaluating useContext.updateCertainIntensity) .Other contexts however, work just fine, but they are not using objects, just simple strings. Does it have to do with using an object in useState()?
You aren't wrapping your app inside the context you just created.
In your App.jsx
<NavigationContainer>
<SliderValueProvider> {/* this one is going to feed its children with data */}
<MyStack /> {/* this will be fed by the parent component */}
</SliderValueProvider>
</NavigationContainer>
Related
I created the Text To Speech function in React Native using the react-native-tts library on Android, but it always shows an error/warn like this
new NativeEventEmitter() was called with a non-null argument without the required addListener method.
new NativeEventEmitter() was called with a non-null argument without the required removeListeners method.
Here's an example from my code.
import React from 'react';
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
import {View, Text, SafeAreaView, TouchableOpacity} from 'react-native';
import Tts from 'react-native-tts';
const TextToVoiceScreen = ({route, navigation}) => {
const handleTextToSpeech = val => {
let stringSpace = val.split('').join(' ');
// Set Engine Voice
Tts.setDefaultEngine('com.google.android.tts');
Tts.getInitStatus().then(
() => {
Tts.stop();
Tts.setDucking(true);
Tts.setDefaultRate(0.09);
Tts.speak(stringSpace, {
androidParams: {
KEY_PARAM_PAN: -1,
KEY_PARAM_VOLUME: 0.9,
KEY_PARAM_STREAM: 'STREAM_MUSIC',
},
});
},
err => {
if (err.code === 'no_engine') {
Tts.requestInstallEngine();
console.log('Install Engine');
}
},
);
};
return (
<SafeAreaView>
<View>
<Text>Test Voice</Text>
<TouchableOpacity onPress={() => handleTextToSpeech('Hello World')}>
<View>
<MaterialCommunityIcons
name="text-to-speech"
color={'#33691e'}
size={20}
/>
</View>
</TouchableOpacity>
</View>
</SafeAreaView>
);
};
export default TextToVoiceScreen;
this is so annoying.
how fix this issues guys..
I am creating a feature to capture pictures with a height/width set and save them in the gallery. At my current stage I can take a photo and save it to the gallery, the only problem is that the saved photo is not the height and width I previously set.
It seems like something simple, but I don't know what I am overlooking.
App.js
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View, SafeAreaView, Image, TouchableOpacity } from 'react-native';
import { useEffect, useRef, useState } from 'react';
import { FontAwesome } from "#expo/vector-icons";
import { Camera } from 'expo-camera';
import { shareAsync } from 'expo-sharing';
import * as MediaLibrary from 'expo-media-library';
import styles from "./styles.js";
export default function App() {
let cameraRef = useRef();
const [hasCameraPermission, setHasCameraPermission] = useState();
const [hasMediaLibraryPermission, setHasMediaLibraryPermission] = useState();
const [photo, setPhoto] = useState();
useEffect(() => {
(async () => {
const cameraPermission = await Camera.requestCameraPermissionsAsync();
const mediaLibraryPermission = await MediaLibrary.requestPermissionsAsync();
setHasCameraPermission(cameraPermission.status === "granted");
setHasMediaLibraryPermission(mediaLibraryPermission.status === "granted");
})();
}, []);
if (hasCameraPermission === undefined) {
return <Text>Requesting permissions...</Text>
} else if (!hasCameraPermission) {
return <Text>Permission for camera not granted. Please change this in settings.</Text>
}
let takePic = async () => {
let options = {
quality: 1,
base64: true,
exif: false
};
};
if (photo) {
let savePhoto = () => {
MediaLibrary.saveToLibraryAsync(photo.uri).then(() => {
setPhoto(undefined);
});
};
return (
<SafeAreaView style={styles.container}>
<Image style={styles.responsiveImage} source={{ uri: "data:image/jpg;base64," + photo.base64 }} resizeMode="contain"/>
{hasMediaLibraryPermission ?
<TouchableOpacity style={styles.buttonSave} onPress={savePhoto}>
<FontAwesome name="save" size={23} color="#fff"></FontAwesome>
</TouchableOpacity> : undefined}
</SafeAreaView>
);
}
return (
<SafeAreaView style={styles.container}>
<Camera style={styles.camera} ref={cameraRef}>
<View style={styles.buttonContainer}>
<TouchableOpacity style={styles.buttonCamera} onPress={takePic}>
<FontAwesome name="camera" size={27} color="#fff"></FontAwesome>
</TouchableOpacity>
</View>
<StatusBar style="auto" />
</Camera>
</SafeAreaView>
);
}
style.js
import { StyleSheet } from "react-native"
const styles = StyleSheet.create({
responsiveImage: {
width: '80%',
height: 400,
},
});
export default styles
In My below code when I use useNavigation() then it gives an error like my quiestion
How to use useNavigation, Please any one can solve this error... ERROR:Couldn't find a navigation object. Is your component inside a screen in a navigator?
I followed code from here https://rnfirebase.io/messaging/notifications#handling-interaction
import React, {useState, useEffect } from 'react';
import messaging from '#react-native-firebase/messaging';
import { NavigationContainer, useNavigation } from "#react-navigation/native";
import { createStackNavigator, HeaderTitle, } from "#react-navigation/stack";
const Stack = createStackNavigator();
function App(props) {
const navigation = props.navigation
//const navigation = useNavigation();
const [initialRoute, setInitialRoute] = useState('Splash Screen');
useEffect(() => {
messaging().onMessage(remoteMessage => {
navigation.navigate("Description Screen");
console.log(props.navigation)
});
}, []);
return (
<NavigationContainer>
<Stack.Navigator
initialRouteName={initialRoute}
headerMode="none"
screenOptions={{
gestureEnabled: true,
}}
>
<Stack.Screen name="Splash Screen" component={SplashScreen} />
<Stack.Screen name="Description Screen" component={DescriptionScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
export default App;
You can't access navigation because it's not ready yet. you can create Ref for your navigation then export it and use it where you want.
// App.js
import { NavigationContainer } from '#react-navigation/native';
import { navigationRef } from './RootNavigation';
export default function App() {
return (
<NavigationContainer ref={navigationRef}>{/* ... */}</NavigationContainer>
);
}
`
Then you can use it by defining and exporting your method
// RootNavigation.js
import * as React from 'react';
export const navigationRef = React.createRef();
export function navigate(name, params) {
navigationRef.current?.navigate(name, params);
}
any way you can use onReadycall back to say that your navigation is ready
// App.js
import { NavigationContainer } from '#react-navigation/native';
import { navigationRef, isReadyRef } from './RootNavigation';
export default function App() {
React.useEffect(() => {
return () => {
isReadyRef.current = false
};
}, []);
return (
<NavigationContainer
ref={navigationRef}
onReady={() => {
isReadyRef.current = true;
}}
>
{/* ... */}
</NavigationContainer>
);
}
We have the following code within I have the method createDrawerNavigator in my App.js file
const RootDrawer = createDrawerNavigator({
Home: { screen: HomeScreen },
Detail: { screen: DetailScreen },
Result: { screen: ResultScreen },
Section : { screen: SectionScreen }
},{
contentComponent : ({ navigation }) => (<SideBar navigation={navigation} />),
initialRouteName: 'Home',
navigationOptions: {
headerStyle: {
backgroundColor: '#26272d',
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
},
transitionConfig: () => ({
transitionSpec: {
duration: 500,
easing: Easing.out(Easing.poly(4)),
timing: Animated.timing,
},
screenInterpolator: sceneProps => {
const { layout, position, scene } = sceneProps;
const { index } = scene;
const height = layout.initHeight;
const translateY = position.interpolate({
inputRange: [index - 1, index, index + 1],
outputRange: [height, 0, 0],
});
const opacity = position.interpolate({
inputRange: [index - 1, index - 0.99, index],
outputRange: [0, 1, 1],
});
return { opacity, transform: [{ translateY }] };
},
}),
});
And I have the screen SideBar that acts as Drawer:
import React, { Component, PureComponent } from 'react';
import { connect } from 'react-redux';
import { Image, StyleSheet, View, TouchableOpacity, Text, Linking } from 'react-native';
import { Icon } from 'native-base';
import {StackActions, NavigationActions, DrawerActions} from 'react-navigation';
import Ionicons from 'react-native-vector-icons/Ionicons';
export default class SideBar extends React.Component {
goTo = (section) => {
const resetAction = StackActions.reset({
index: 0,
actions: [
NavigationActions.navigate({ routeName: 'Section' })
]
})
return () => this.props.navigation.dispatch(resetAction);
}
render() {
return(
<View style={styles.container}>
<View>
<View style={styles.logo}><Image source={require('./images/ln-header-bg.jpg')} style={styles.ln_logo} resizeMode="contain" /></View>
<TouchableOpacity style={styles.link_menu} onPress={() => { this.goTo('all'); }}><Text style={styles.link_menu_text}>Últimas noticias</Text></TouchableOpacity>
<TouchableOpacity style={styles.link_menu} onPress={() => { this.goTo(68); }}><Text style={styles.link_menu_text}>La Nación</Text></TouchableOpacity>
<TouchableOpacity style={styles.link_menu} onPress={() => { this.goTo(69); }}><Text style={styles.link_menu_text}>El Mundo</Text></TouchableOpacity>
<TouchableOpacity style={styles.link_menu} onPress={() => { this.goTo(70); }}><Text style={styles.link_menu_text}>Gente</Text></TouchableOpacity>
<TouchableOpacity style={styles.link_menu} onPress={() => { this.goTo(97); }}><Text style={styles.link_menu_text}>#YoParticipo</Text></TouchableOpacity>
</View>
<View>
<Text style={styles.follow_social}>Síguenos en las redes</Text>
<View style={styles.follow_social_links}>
</View>
</View>
</View>
)
}
}
In the SideBar I want to call an function located in Home Component, I tried with react navigation dispacth method but doesn't working.
What I have to call the function or navigate to another screen? Can some help me please?
Thanks!
I never used drawers from react-navigation, but I would assume that the way they work is similar to stackNavigators. So, assuming that, what you could do was to set a navigation parameter in the Home screen, for example, inside the componentDidMount() method, like so:
this.props.navigation.setParams({ 'paramName': paramValue });
and then, in the drawer, in the componentWillMount() method, you could do something like:
const var_x = this.props.navigation.getParam('paramName', null);
This way, you can either send the function itself as a parameter, or send a reference to the Home screen, and then access its methods from the drawer.
ps: on both calls, paramName needs to be a string.
ps2: in the getParam method call, the second argument, in the example, null, is the default value in case there is not a value for the requested parameter.
Again, I use this method for stackNavigators, so you might take a look at the react-navigation documentation to double check if there is any difference for drawer: https://reactnavigation.org/docs/en/drawer-navigator.html#docsNav
I am new in react-native and i want to open url in default browser like Chrome in Android and iPhone both.
We open url via intent in Android same like functionality i want to achieve.
I have search many times but it will give me the result of Deepklinking.
You should use Linking.
Example from the docs:
class OpenURLButton extends React.Component {
static propTypes = { url: React.PropTypes.string };
handleClick = () => {
Linking.canOpenURL(this.props.url).then(supported => {
if (supported) {
Linking.openURL(this.props.url);
} else {
console.log("Don't know how to open URI: " + this.props.url);
}
});
};
render() {
return (
<TouchableOpacity onPress={this.handleClick}>
{" "}
<View style={styles.button}>
{" "}<Text style={styles.text}>Open {this.props.url}</Text>{" "}
</View>
{" "}
</TouchableOpacity>
);
}
}
Here's an example you can try on Expo Snack:
import React, { Component } from 'react';
import { View, StyleSheet, Button, Linking } from 'react-native';
import { Constants } from 'expo';
export default class App extends Component {
render() {
return (
<View style={styles.container}>
<Button title="Click me" onPress={ ()=>{ Linking.openURL('https://google.com')}} />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
},
});
A simpler way which eliminates checking if the app can open the url.
loadInBrowser = () => {
Linking.openURL(this.state.url).catch(err => console.error("Couldn't load page", err));
};
Calling it with a button.
<Button title="Open in Browser" onPress={this.loadInBrowser} />
Try this:
import React, { useCallback } from "react";
import { Linking } from "react-native";
OpenWEB = () => {
Linking.openURL(url);
};
const App = () => {
return <View onPress={() => OpenWeb}>OPEN YOUR WEB</View>;
};
Hope this will solve your problem.
In React 16.8+, the following can be used to create an ExternalLinkBtn component for opening external links in the browser.
import React from 'react';
import { Button, Linking } from 'react-native';
const ExternalLinkBtn = (props) => {
return <Button
title={props.title}
onPress={() => {
Linking.openURL(props.url)
.catch(err => {
console.error("Failed opening page because: ", err)
alert('Failed to open page')
})}}
/>
}
Below is an example of using our ExternalLinkBtn component
export default function exampleUse() {
return (
<View>
<ExternalLinkBtn title="Example Link" url="https://example.com" />
</View>
)
}