JSON Parse Error : Unexpected Identifier "Undefined"(React Native) - json

I'm trying to use Async storage to store two Text Input values stored as an object and pass it to a different view where they'll be displayed on a button press.
As mentioned in other StackOverflow posts I've used JSON.parse and JSON.stringify to pass the object as JSON data, still for some reason I;m getting the error JSON Parse Error: Unexpected Identifier "Undefined"(React Native)
Add Data
class AddData extends React.Component {
constructor(props) {
super(props);
this.state = {
text1: '' ,
text2: ''
};
}
render() {
function BtnPress() {
alert('Hi')
}
return (
<View style={{flex: 1, flexDirection: 'column', justifyContent:'center', alignItems: 'center'}}>
<TextInput
style={{height: 40,width:200}}
onChangeText={(text1) => this.setState({input1: text1})}
/>
<TextInput
style={{height: 40,width:200}}
onChangeText={(text2) => this.setState({input2: text2})}
/>
<Button
onPress={() => {
AsyncStorage.setItem('user', JSON.stringify({
name:'Rohit',
email: 'rohitgird12gmail.com'
}));
this.props.navigation.navigate('Home', {});
}}
title="Submit"
/>
</View>
);
}
}
View to Display Data
class DetailsScreen extends React.Component {
displayName = async ()=> {
try {
const myArray = await AsyncStorage.getItem('user');
if (myArray !== null) {
alert(JSON.parse(myArray.name));
}
} catch (error) {
alert(error)
}
}
render() {
return (
<View style={{flex: 1, flexDirection: 'column', justifyContent:'center', alignItems: 'center'}}>
<Button
onPress={this.displayName}
title="Get Data"
/>
</View>
);
}
}

It looks like const myArray = await AsyncStorage.getItem('user'); is returning undefined while you defended yourself from null only, which is not sufficient here.
Antoher possible problem lies here : JSON.parse(myArray.name). Are you sure it's not supposed to be JSON.parse(myArray).name?

Related

ReactNative HTMLButtonElement gives error at emulator

I have the following code:
import React from 'react';
import {StyleSheet, View} from 'react-native';
interface MyButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
dataCode: string;
}
class MyButton extends React.Component<
MyButtonProps & React.HTMLProps<HTMLButtonElement>,
{}
> {
render() {
return <button {...this.props} />;
}
}
const App = () => {
const _onPressButton = (event: any) => {
let params: string = (event.currentTarget as MyButton).props.dataCode;
fetch(`http://10.18.1.19/switch?${params}`);
};
return (
<View style={styles.container}>
<View style={styles.buttonContainer}>
<MyButton
dataCode="binary=111111111111111111111111&protocol=1&pulselength=3"
onClick={_onPressButton}
title="Test"
/>
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
},
buttonContainer: {
margin: 20,
},
});
export default App;
and I have error message when I use button ws. Button.
ReactNativeJS: Invariant Violation: View config getter callback for
component button must be a function (received undefined). Make
sure to start component names with a capital letter.
How can I extend a HTML button element?

Call function to update Context in React Native

I am having problems calling a function in React Native. I simply want to change the value of 'Context'. Here is some code, first the script for 'context':
//LogContext.js
import React, { useState } from 'react'
export const LogContext = React.createContext({
set: "en",
login: "false"
})
export const LogContextProvider = (props) => {
const setLog = (login) => {
setState({set: "jp", login: login})
}
const initState = {
set: "en",
login: "false"
}
const [state, setState] = useState(initState)
return (
<LogContext.Provider value={state}>
{props.children}
</LogContext.Provider>
)
}
and the 'app.js' code:
//app.js
import React, { useState, useContext } from 'react';
import { Button, Text, TextInput, View } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import { LogContextProvider, LogContext } from './LogContext'
function HomeScreen({ navigation }) {
const state = useContext(LogContext);
return (
<>
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Passed config: {JSON.stringify({state})}</Text>
<Text>Home Screen</Text>
</View>
{state.login === 'false' ? (
<Button
title="Go to Login"
onPress={() => navigation.navigate('Login')}
/>
) : (
<Button title="Stuff" onPress={() => navigation.navigate('DoStuff')} />
)}
</>
);
}
function LoginScreen({ navigation }) {
const state = useContext(LogContext);
//do stuff to login here...
state.setLog('true'); //not functional...
return (
<LogContext.Provider value={'true'}> //value={'true'} also not functional...
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Login Screen</Text>
<Button title="Go to Home" onPress={() => navigation.navigate('Home')} />
</View>
</LogContext.Provider>
);
}
function StuffScreen({ navigation }) {
//do other stuff here...
}
const Stack = createStackNavigator();
function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Login" component={LoginScreen} />
<Stack.Screen name="DoStuff" component={StuffScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
export default App;
Obviously I am not too familiar with React Native. Any advice on how to call the "setLog()" function as to enable an update of the value for the 'Context' global variable would be greatly appreciated. I thank you in advance.
I am trying to modify my "App()" function to wrap the Navigator within the provider as suggested by another user...however this following is completely non-functional...suggestions appreciated:
const Stack = createStackNavigator();
function App() {
const [data, setData] = useState({
set: 'en',
login: 'false',
});
const state = { data, setData };
return (
<LogContext.Provider value={state}>
<NavigationContainer>
{state.data.login === 'true' ? (
<Stack.Navigator>
<Stack.Screen name="BroadCast" component={VideoScreen} />
<Stack.Screen name="Logout" component={LogoutScreen} />
</Stack.Navigator>
) : (
<Stack.Navigator>
<Stack.Screen name="Login" component={LoginScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
<Stack.Screen name="Home" component={HomeScreen} />
</Stack.Navigator>
)}
</NavigationContainer>
</LogContext.Provider>
);
}
The issue you are having is not having a set function in your context and i dont see a need for a separate LogContext provider function.
You can simply do that part in your app.js or whatever the root function. The below example does that. You can see how a state value is passed along with a function to set the values and this can be modified from teh Login component which is inside the provider. If you use a separate provider its a bit confusing. The below is a working example without the navigation part to give you an idea.
const LogContext = createContext({
data: {
set: 'en',
login: 'false',
},
});
export default function App() {
const [data, setData] = useState({
set: 'en',
login: 'false',
});
const state = { data, setData };
return (
<LogContext.Provider value={state}>
<View style={{ flex: 1 }}>
<Text>{JSON.stringify(state.data)}</Text>
<Login />
</View>
</LogContext.Provider>
);
}
const Login = () => {
const state = React.useContext(LogContext);
return (
<View>
<Button
onPress={() => state.setData({ set: 'bb', login: 'true' })}
title="Update"
/>
</View>
);
};
To modify your code, you should wrap the main navigator inside the LogContext.Provider and maintain the state there which will help you do the rest.
Feel free to ask any further clarification :)

Need to dynamically add items into a drawer menu in React Native

I need to have some items dynamically in my app's drawer after some categories get fetched from a json file (https://www.rallyssimo.it/wp-json/wp/v2/categories)
json example (I need that information)
[
{
"id": 44,
.
.
"name": "ALTRI RALLY",
.
.
},
Tis is the drawer:
const CustomDrawerComponent = (props) => (
<SafeAreaView style={{flex:1}}>
<View style={{height:80, backgroundColor: 'white', alignItems: 'center', justifyContent: 'center'}}>
<Image
source={{uri: 'https://www.rallyssimo.it/wp-content/uploads/2016/08/rallyssimo-logo.png'}}
style={{ height: 60, width: 180}}
/>
</View>
<ScrollView>
<DrawerItems {...props} />
</ScrollView>
</SafeAreaView>
)
const AppNavigator = createDrawerNavigator(
{
Home: DashboardStackNavigator,
},
{
contentComponent: CustomDrawerComponent
}
);
const AppContainer = createAppContainer(AppNavigator);
//Main class
export default class App extends React.Component {
render() {
return <AppContainer />;
}
}
How can I put the items (I'm going to get from the JSON) in the drawer?
As you have noticed, you need to create your own custom drawer to achieve this, which is done with contentComponent: CustomDrawerComponent.
Now you cannot use DrawerItems within CustomDrawerComponent since you want full control on the items listed. But you can recreate the items yourself using basic and elements.
Finally you need to fetch the API and store the data in your state in order to render the result as a list in the drawer.
Here is a basic example for :
import React, { Component } from 'react';
import { ScrollView, Text, View, Image } from 'react-native';
import { NavigationActions } from 'react-navigation';
class CustomDrawerComponent extends Component {
constructor(props) {
super(props);
this.state = { data: null };
}
async componentDidMount() {
fetch('https://www.rallyssimo.it/wp-json/wp/v2/categories')
.then(res => res.json())
.then(data => this.setState({ data }))
}
navigateToScreen(routeName, params) {
return () => { this.props.navigation.dispatch(NavigationActions.navigate({ routeName, params })) };
}
render() {
if (this.state.data === null) {
return <Text>...</Text>;
}
return (
<View style={{ flex: 1, paddingTop: 30 }}>
<View style={{height:80, backgroundColor: 'white', alignItems: 'center', justifyContent: 'center'}}>
<Image
source={{uri: 'https://www.rallyssimo.it/wp-content/uploads/2016/08/rallyssimo-logo.png'}}
style={{ height: 60, width: 180}}
/>
</View>
<ScrollView>
<View>
{this.state.data.map(x => (
<Text
key={x.id}
style={{ fontSize: 16, lineHeight: 30, textAlign: 'center' }}
onPress={this.navigateToScreen('page2')}
>
{x.name}
</Text>
))}
</View>
</ScrollView>
</View>
);
}
}
export default CustomDrawerComponent;
And here is a working snack.

How to set this.props.key into the Firebase database reference in react native

I have retrieved the values from the other component and displayed in the TextInput for users to edit the values which are the (itemTitle: this.props.title, itemIng: this.props.ing, itemSteps: this.props.steps) and now
I'm trying to update the values back to firebase after user pressed the button in modal. But I'm having a problem to get the firebase database reference, I'm able get the {this.props._key} from another component but when I write as a .child(itemKey) it's not working and shows "Can't find variable: itemKey" Does anyone has the similar problem?
import React, { Component } from 'react';
import {
Platform,
StyleSheet,
Text,
View,
ScrollView,
Button,
TouchableHighlight,
Modal,
TextInput,
ImageBackground
} from 'react-native';
import {Actions}from 'react-native-router-flux';
import firebase from './firebase';
const remote = 'http://l.rgbimg.com/cache1oCOq1/users/b/ba/ba1969/600/mxc1dae.jpg';
export default class RecipeDetails extends React.Component{
constructor(props){
super(props);
this.state={
modalVisible: false,
itemTitle: this.props.title,
itemIng: this.props.ing,
itemSteps: this.props.steps,
itemKey: this.props._key.toString(),
};
this.vegeRef = this.getRef().child('Vegetarian').child(itemKey);
this.fastRef = this.getRef().child('Fast Food');
this.hpRef = this.getRef().child('Healthy');
}
setModalVisible(visible){
this.setState({modalVisible:visible});
}
getRef(){
return firebase.database().ref();
}
updateItem(){
this.setModalVisible(true);
}
render(){
return(
<View style={styles.container}>
<Modal
visible={this.state.modalVisible}
animationType={'slide'}
onRequestClose={() => {}}
>
<Text>Edit the details and Update.</Text>
<TextInput
value={this.state.itemTitle}
onChangeText ={(itemTitle) => this.setState({ itemTitle })}
/>
<TextInput
value={this.state.itemIng}
onChangeText ={(itemIng) => this.setState({itemIng})}
/>
<TextInput
value={this.state.itemSteps}
onChangeText ={(itemSteps) => this.setState({itemSteps})}
/>
<View style={styles.modalContainer}>
<View style={styles.innerContainer}>
<Button onPress={() => {
this.vegeRef.update({title:this.state.itemTitle, ing:this.state.itemIng, steps:this.state.itemSteps});
this.setModalVisible(!this.state.modalVisible)
}}
title="Save Recipe"
>
</Button>
<Button
onPress={() => this.setModalVisible(!this.state.modalVisible)}
title="Cancel"
>
</Button>
</View>
</View>
</Modal>
<ImageBackground
style={{
flex: 1,
justifyContent: 'center',
paddingVertical: 35
}}
source={{ uri: remote }}
>
<ScrollView style={styles.container2} showsVerticalScrollIndicator={false}>
<Text style={styles.heading1}>
Ingredients
</Text>
<Text style={styles.heading2}>
{this.props.ing}
{this.props._key}
</Text>
<Text style={styles.heading1}>
Steps
</Text>
<Text style={styles.heading2}>
{this.props.steps}
</Text>
</ScrollView>
</ImageBackground>
<View style={styles.action}>
<TouchableHighlight
underlayColor='#24ce84'
onPress={this.updateItem.bind(this)}
>
<Text style = {styles.actionText}>Update Recipe</Text>
</TouchableHighlight>
</View>
</View>
);
}
}
This is the Firebase JSON format
"Vegetarian" : {
"-L3RaWBQchF5rKmVtpNk" : {
"ing" : "Aasaaaa",
"steps" : "Aa",
"title" : "Eeww"
},
"-L3WdmePSwkWNN4xB51M" : {
"ing" : "This is good",
"steps" : "Nice",
"title" : "Salad"
},
You need to change the value ot itemKey to this.state.itemKey and that will not be inside constructor as your are initialising the states in constructor. Also whenever you are calling any function like you have called update to update the values. Try to use the update query of firebase inside a function and use that in onPress event of Button react element. Please check modified code.
import React, { Component } from 'react';
import {
Platform,
StyleSheet,
Text,
View,
ScrollView,
Button,
TouchableHighlight,
Modal,
TextInput,
ImageBackground
} from 'react-native';
import { Actions } from 'react-native-router-flux';
import firebase from './firebase';
const remote = 'http://l.rgbimg.com/cache1oCOq1/users/b/ba/ba1969/600/mxc1dae.jpg';
export default class RecipeDetails extends React.Component {
constructor(props) {
super(props);
this.state = {
modalVisible: false,
itemTitle: this.props.title,
itemIng: this.props.ing,
itemSteps: this.props.steps,
itemKey: this.props._key.toString(),
};
// this.vegeRef = this.getRef();
this.fastRef = this.getRef().child('Fast Food');
this.hpRef = this.getRef().child('Healthy');
}
componentDidMount() {
this.getRef().child('Vegetarian').on('child_added', s => {
if (s.exists()) {
console.log(s.val()) // It will return the new updated object
console.log(s.key) // It will return the timestamp key
this.setState({
itemTitle: s.val().title,
itemIng: s.val().ing,
itemSteps: s.val().steps,
})
}
})
}
setModalVisible(visible) {
this.setState({ modalVisible: visible });
}
getVegRef = () => {
this.getRef().child('Vegetarian').child(this.state.itemKey)
}
getRef = () => {
return firebase.database().ref();
}
updateVeg = () => {
this.getVegRef().update(
{
title: this.state.itemTitle,
ing: this.state.itemIng,
steps: this.state.itemSteps
});
this.setModalVisible(!this.state.modalVisible)
}
updateItem() {
this.setModalVisible(true);
}
render() {
return (
<View style={styles.container}>
<Modal
visible={this.state.modalVisible}
animationType={'slide'}
onRequestClose={() => { }}
>
<Text>Edit the details and Update.</Text>
<TextInput
value={this.state.itemTitle}
onChangeText={(itemTitle) => this.setState({ itemTitle })}
/>
<TextInput
value={this.state.itemIng}
onChangeText={(itemIng) => this.setState({ itemIng })}
/>
<TextInput
value={this.state.itemSteps}
onChangeText={(itemSteps) => this.setState({ itemSteps })}
/>
<View style={styles.modalContainer}>
<View style={styles.innerContainer}>
<Button onPress={
this.updateVeg
}
title="Save Recipe"
>
</Button>
<Button
onPress={() => this.setModalVisible(!this.state.modalVisible)}
title="Cancel"
>
</Button>
</View>
</View>
</Modal>
<ImageBackground
style={{
flex: 1,
justifyContent: 'center',
paddingVertical: 35
}}
source={{ uri: remote }}
>
<ScrollView style={styles.container2} showsVerticalScrollIndicator={false}>
<Text style={styles.heading1}>
Ingredients
</Text>
<Text style={styles.heading2}>
{this.props.ing}
{this.props._key}
</Text>
<Text style={styles.heading1}>
Steps
</Text>
<Text style={styles.heading2}>
{this.props.steps}
</Text>
</ScrollView>
</ImageBackground>
<View style={styles.action}>
<TouchableHighlight
underlayColor='#24ce84'
onPress={this.updateItem.bind(this)}
>
<Text style={styles.actionText}>Update Recipe</Text>
</TouchableHighlight>
</View>
</View>
);
}
}

react native pass function to child component as a prop (this.props.functionName is not a function)

I've seen this question a lot of other places too, but for some reason no matter what i do, binding or declaring differently, i keep receiving the same error that _this3.props.toggleProp() is not a function. (In '_this3.props.toggleProp()', '_this3.props.toggleProp is undefined.)
my parent component is:
constructor (props) {
super(props)
this.state = {
selectedTab: 'home',
notificationNumber: -1,
}
this._toggleScreen = this._toggleScreen.bind(this);
this.toggleSchedule = this.toggleSchedule.bind(this);
}
_toggleScreen() {
this.setState({
selectedTab: 'categories',
})
}
render(): React$Element<any> {
function MainContent(props) {
const selectedTab = props.selectedTab;
if (selectedTab === 'home') {
return <Home toggleProp={this._toggleScreen} grain="this one here"/>;
}
if (selectedTab === 'categories') {
return <Categories toggleScreen={this.toggleScreen} />;
}
return <Schedule />;
}
return (
<View style={styles.container}>
<MainContent selectedTab={this.state.selectedTab} style={styles.content}/>
</View>
);
}
}
and the important part of my child component is:
render(): React$Element<any> {
return (
<Icon.Button name="home" backgroundColor="rgba(0,0,0,0)" onPress={()=>{this.props.toggleProp()}}>
</Icon.Button>
i have constructor (props) {
super(props)
at the top. any ideas what's going on?
onPress is not a react SyntheticEvent
https://facebook.github.io/react/docs/events.html
change onPress for onClick and it should work.
here is a codesand with onClick working just fine.
https://codesandbox.io/s/93ZyOWl8
The function in your parent component is _toggleScreen() {}, however you're passing in this.toggleScreen instead of this._toggleScreen into your Categories component. This is part of what is causing the toggleProp() is not a function error.
if (selectedTab === 'categories') {
return <Categories toggleScreen={this._toggleScreen} />;
}
Additionally, you're using toggleProp as the prop in the <Home /> Component, but are using toggleScreen as the prop in your Categories component, so this would also throw a toggleProp is undefined error.
A working render function should look like this:
render(): React$Element<any> {
function MainContent(props) {
const selectedTab = props.selectedTab;
if (selectedTab === 'home') {
return <Home toggleProp={this._toggleScreen} grain="this one here"/>;
}
if (selectedTab === 'categories') {
return <Categories toggleProp={this._toggleScreen} />;
}
return <Schedule />;
}
return (
<View style={styles.container}>
<MainContent selectedTab={this.state.selectedTab} style={styles.content}/>
</View>
);
}
I actually needed to pass the function down two children, I totally forgot that I'm rendering the content in MainContent, so I need to pass the toggleScreen as a prop in the mainContent, then pass this.prop._toggleScreen to the home component then call it in there as a prop again.
handler(e) {
this.setState({
selectedTab: 'categories',
})
}
render(): React$Element<any> {
function MainContent(props) {
const selectedTab = props.selectedTab;
if (selectedTab === 'home') {
return <Home handler={props.handler} grain={props.selectedTab} />;
}
else if (selectedTab === 'categories') {
return <Categories toggleScreen={this.toggleScreen} />;
}
return <Schedule />;
}
return (
<View style={styles.container}>
<MainContent selectedTab={this.state.selectedTab} style={styles.content} handler={this.handler}/>
</View>
);
}
}