Unable to store data in redux store -Data disappears after refreshing the page - react-native

I am new to react-native and learning react-redux. I went to a website and copied the exact code. The code is not storing values of email and password. When I refresh the page all the data disappears. Can anyone help me to save data in redux-store persistently? Any help would be highly appreciated.
Here is my App.js
import React from 'react';
import { Provider } from 'react-redux';
import store from '../redux/store';
import Form from './components/Form';
export default function App() {
return (
<Provider store={store}>
<Form />
</Provider>
);
}
And my Form.js
import React from 'react';
import { View, Button, TextInput, StyleSheet } from 'react-native';
import { Field, reduxForm } from 'redux-form';
const Form = (props) => {
const { handleSubmit } = props;
const onSubmit = (values) => console.log(values);
const renderInput = ({ input: { onChange, ...input }, ...rest}) => {
return <TextInput style={styles.input} onChangeText={onChange} {...input} {...rest} />
};
return (
<View style={styles.root}>
<Field
name={'email'}
props={{
placeholder: 'Email'
}}
component={renderInput}
/>
<Field
name={'password'}
props={{
placeholder: 'Password',
secureTextEntry: true
}}
component={renderInput}
/>
<Button title={'Submit'} onPress={handleSubmit(onSubmit)} />
</View>
);
};
const styles = StyleSheet.create({
root: {
flex: 1,
padding: 32,
justifyContent: 'center'
},
input: {
padding: 8,
marginBottom: 8,
borderColor: 'blue',
borderWidth: 1,
borderRadius: 4
}
});
export default reduxForm({form: 'test-form'})(Form);
My store.js
import {combineReducers, createStore} from 'redux';
import {reducer as formReducer} from 'redux-form';
const rootReducer = combineReducers({
form: formReducer
});
const store = createStore(rootReducer);
export default store;

To persist your data you need to use redux-persist.
here is the Github link

Related

React Native - searchApi is not a function

I am new in React Native. I try to create a simple searching food restaurant with Yelp. Unfortunately, I get an error:
"searchApi is not a function. (in 'searchApi(term)', 'searchApi' is
"")
Below my code.
useResults.js
import React, { useEffect, useState } from 'react';
import yelp from '../api/yelp';
export default () => {
const [result, setResult] = useState([]);
const [errorMessage, setErrorMessage] = useState('');
const searchApi = async (searchTerm) => {
console.log("hi there");
try {
const response = await yelp.get('/search', {
params: {
limit: 50,
term: searchTerm,
location: 'san jose'
}
});
setErrorMessage(null);
setResult(response.data.businesses);
} catch (err) {
setErrorMessage('Something Went Wrong');
}
};
/*
useEffect(() => {}); //Run the arrow function everytime the component is rendered
useEffect(() => {}, []); // Run the arrow function only when the component is first rendered
useEffect(() => {}, [value]); // Run the arrow function only when the component is first rendered, and when the value is changes
*/
useEffect(() => {
searchApi('pasta');
}, []);
return [searchApi, result, errorMessage];
};
SearchScreen.js
import React, { useEffect, useState } from 'react';
import { View, Text, StyleSheet } from 'react-native';
import ResultList from '../components/ResultList';
import SearchBar from '../components/SearchBar';
import useResults from '../hooks/useResults';
const SearchScreen = () => {
const [term, setTerm] = useState('');
const [searchApi, result, errorMessage] = useResults();
console.log(result);
return (
<View>
<SearchBar
term={term}
onTermChange={setTerm}
onTermSubmit={() => searchApi(term)}
/>
<View>{errorMessage ? <Text>{errorMessage}</Text> : null}</View>
<Text>We have found {result.length} results</Text>
<ResultList title="Cost Effective" />
<ResultList title="Bit Pricier" />
<ResultList title="Big Spender"/>
</View>
);
};
const styles = StyleSheet.create({
});
export default SearchScreen;
edit :
SearchBar.js
import React from 'react';
import { View, Text, StyleSheet, TextInput } from 'react-native';
import { Feather } from '#expo/vector-icons';
const SearchBar = ({ term, onTermChange, onTermSubmit }) => {
return (
<View style={styles.backgroundStyle}>
<Feather style={styles.iconStyle} name="search" size={30} color="black" />
<TextInput style={styles.inputStyle}
autoCapitalize="none"
autoCorrect={false}
placeholder="Search"
value={term}
onChangeText={onTermChange}
onEndEditing={onTermSubmit}
/>
</View>
)
};
const styles = StyleSheet.create({
backgroundStyle: {
marginTop: 10,
backgroundColor: '#F0EEEE',
height: 50,
borderRadius: 5,
marginHorizontal: 15,
flexDirection: 'row'
},
inputStyle: {
flex: 1,
fontSize: 18,
marginHorizontal: 10
},
iconStyle: {
fontSize: 35,
alignSelf: 'center'
}
});
export default SearchBar;
When I type in search bar and hit done button, I got the error above.
Seems in useResults.js file this: return [searchApi, result, errorMessage]; does not properly return the function. But the result and errorMessage return successfully.
And in this file: SearchScreen.js the error line is shown in here: onTermSubmit={() => searchApi(term)}.
How to fix this?
Try adding a callback to onChangeText.
<TextInput style={styles.inputStyle}
autoCapitalize="none"
autoCorrect={false}
placeholder="Search"
value={term}
onChangeText={() => onTermChange()} // Add fat arrow function here
onEndEditing={onTermSubmit}
/>

Pass Input value to parent component function

I'm trying to develop a react-native APP.
I'm very experienced with Java & PHP, but something is puzzling me with react-native.
Basically, I'm trying to obtain a working Login PAGE (just for practical exercise) but I'm struggling when I try to pass value from child component value (for example, the Password Input) to parent component function (the LoginForm).
Here's a specific code:
[PasswordInput]
import * as React from 'react';
import { View } from 'react-native';
import { HelperText, TextInput } from 'react-native-paper';
class PasswordInput extends React.Component {
constructor(props){
super(props);
this.state ={
password:''
};
}
getPassword() {
return this.state.password;
}
login(){
alert(this.state.password)
}
OnChangesValue(e){
console.log(e.nativeEvent.text);
this.setState({
userName :e.nativeEvent.text,
})
}
changePassword(e){
console.log(e.nativeEvent.text);
this.setState({
password :e.nativeEvent.text,
})
}
hasErrors(text){
let result=true;
if(text.length>10 || text.length==0){
result=false;
}
return result;
};
render() {
return (
<View>
<TextInput
ref="pass"
name="password"
onChange={this.changePassword.bind(this)}
secureTextEntry={true}
label="Password"
left={<TextInput.Icon name="lock" onPress={() => {
}}/>}
/>
<HelperText type="error" visible={this.hasErrors(this.state.password)}>
Password too short!
</HelperText>
</View>
);
}
}
export default PasswordInput;
and here the LoginForm component:
import * as React from 'react';
import { Component, createRef } from "react";
import {View, StyleSheet} from 'react-native';
import {Button, Card, Title} from 'react-native-paper';
import EmailInput from './login_components/email_input';
import PasswordInput from './login_components/password_input';
import {useRef} from 'react/cjs/react.production.min';
class LoginForm extends React.Component {
passwordInput = createRef();
submitForm(){
alert(this.passwordInput['password'].value);
}
render() {
return (
<Card style={styles.detailRowContainer}>
<Card.Title
title="Signup!"
subtitle="Inserisci i tuoi dati per eseguire il login"
/>
<EmailInput/>
<PasswordInput ref={this.passwordInput}/>
<Card.Actions>
<Button mode="contained" type="submit" style={styles.loginButtonSection} onPress={() => this.submitForm()}>
LOGIN
</Button>
</Card.Actions>
</Card>
);
}
}
const styles = StyleSheet.create({
loginButtonSection: {
width: '100%',
height: '30%',
justifyContent: 'center',
alignItems: 'center'
},
detailRowContainer: {
flex:1,
flexDirection:'row',
alignItems:'center',
justifyContent:'center'
},
});
export default LoginForm;
My goal (for now) is to understand how to receive the PasswordInput value in my LoginForm component in order to print the password in the alert (submitForm() function).
Perhaps easier would be to go about it in the opposite direction and have a reusable component which is given props to alter its appearance and functionality:
Landing page:
// importing Input.tsx from folder: components
import Input from '../components/Input';
export default function LandingScreen() {
// Hooks for email and password
const [email, set_email] = useState<string>('');
const [password, set_password] = useState<string>('');
return(
<View>
<Input
placeholder="Email"
onChangeText={(text) => set_email(text)}
keyboardType="email-address"
/>
<Input
placeholder="Password"
onChangeText={(text) => set_password(text)}
secureTextEntry={true}
keyboardType="default"
/>
</View>
)
and here is an example of an Input component:
(so instead of passing information from an child to parent we now have a reusable component which accepts a few props defined in its interface)
imported Input.tsx found in folder: components
import React, { FC } from 'react';
import { View, StyleSheet, useWindowDimensions } from 'react-native';
import { TextInput } from 'react-native-gesture-handler';
interface Props {
placeholder: string;
onChangeText: (text: string) => void;
secureTextEntry?: boolean;
keyboardType: any;
}
const Input: FC<Props> = (props) => {
const { width } = useWindowDimensions();
return (
<View style={styles.container}>
<TextInput
style={[styles.input, { width: width * 0.8 }]}
autoCapitalize={'none'}
placeholder={props.placeholder}
secureTextEntry={props.secureTextEntry}
onChangeText={props.onChangeText}
keyboardType={props.keyboardType}
placeholderTextColor={'black'}
/>
</View>
);
};
export default Input;
const styles = StyleSheet.create({
container: {
alignSelf: 'center',
backgroundColor: '#e3e3e3',
borderRadius: 5,
marginVertical: 10,
},
input: {
padding: 15,
},
});
a great way to get started with a sign in screen is with "formik" and "yup" which enables quick creation of input fields and client-side validation with hooks.

How can I get the text / value of a textinput by its ref?

In my parent I have this code:
So I render inside it my custom inputs by this way:
My doubt is how I can access on any part of this parent the text of each input using the ref. Someone can help me?
The textinput component:
https://gist.github.com/ThallyssonKlein/4e054bc368ebc153fbf9222e304ff887
I couldn't solve the problem, apparently there is no way to get this property in pure React-Native.
So I started using the TextInput component of the react-native-paper package. This way the same code worked, I can get the text now with this excerpt:
console.log(refContainerStep1.current.state.value);
use useRef() instead of createRef();
const textInput = useRef(null);
<TextInput
ref={textInput}
....../>
You can access the ref via refContainerStep1.current.
What you can then do is check the Prototype property to check which methods you can use.
I noticed there's a function called _getText which can be used to obtain a value.
An example of grabbing the value in an onPress:
const onPress = () => {
console.log(refContainerStep1.current.__proto__); // See available methods
console.log(refContainerStep1.current._getText()); // Grab the value
}
Do it that way
const onButtonClick = () => {
console.log('get value from parent')
console.log(ref1.current.props.value)
console.log(ref2.current.props.value)
};
Example in expo
Parent
import * as React from 'react';
import { Text, View, StyleSheet,TextInput } from 'react-native';
import Constants from 'expo-constants';
import MyTextInput from './components/AssetExample';
import { Card } from 'react-native-paper';
export default function App() {
const ref1 = React.createRef();
const ref2 = React.createRef();
const onButtonClick = () => {
console.log(ref1.current.props.value)
console.log(ref2.current.props.value)
};
return (
<View style={styles.container}>
<Card>
<button onClick={onButtonClick}>get value</button>
<MyTextInput label={'label 2'} secure={false} ref={ref1} />
<MyTextInput label={'label 1'} secure={true} ref={ref2} />
</Card>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
});
Child
import React, { useState, useEffect } from 'react';
import { TextInput as RnTextInput, StyleSheet, View, Text } from 'react-native';
const styles = StyleSheet.create({
textInput: {
padding: 10,
marginRight: 10,
marginLeft: 10,
borderRadius: 50,
},
text: {
marginLeft: 20,
marginBottom: 10,
fontSize: 20,
},
});
const TextInput = React.forwardRef((props, ref) => {
const [text, setText] = useState('');
return (
<View>
{props.label && <Text style={styles.text}>{props.label}</Text>}
<RnTextInput
style={styles.textInput}
value={text}
onChange={(e) => {
setText(e.target.value);
}}
secureTextEntry={props.secure}
ref={ref}
/>
</View>
);
});
export default TextInput;

invariant violation: element type is invalid React native

I'm trying to import a component into my App.js class but when I try I get the error in my android emulator
invariant violation element type is invalid: expected a string or a class/function but got undefined you likely forgot to export your component from the file its defined in, or you might have mixed up default and named imports
check the render method of 'login'
my problem is that I checked that i'm importing a default import of the login component in my App.js and I am exporting the Login component correctly from what I can tell:
import React, {Component} from 'react';
import {StyleSheet,ScrollView,View,Text,Input,Button,SecureTextEntry,ActivityIndicator} from 'react-native';
import * as firebase from 'firebase';
import auth from '#react-native-firebase/auth';
import {
Header,
LearnMoreLinks,
Colors,
DebugInstructions,
ReloadInstructions,
} from 'react-native/Libraries/NewAppScreen';
export default class Login extends Component {
state={
email: '',
password: '',
authenticating: false
};
componentDidMount(){
const firebaseConfig = {
apiKey: 'garbagekey',
authDomain: 'garbage auth domain'
}
firebase.initializeApp(firebaseConfig)
}
onButtonPress = () =>{
console.log("button pressed")
this.setState({authenticating:true})
}
contentBoolRender = () =>{
if(this.state.authenticating===true){
return(
<View>
<ActivityIndicator size="large"/>
</View>
)
}
return(
<View>
<Input
placeholder="Enter your Email..."
label = "Email"
onChangeText = {email => this.setState({email})}
value = {this.state.email}
/>
<Input
placeholder="Enter your Password..."
label = "Password"
onChangeText = {password => this.setState({password})}
value = {this.state.password}
SecureTextEntry
/>
<Button title="login" onpress={()=>this.onButtonPress()}></Button>
</View>
)
}
render() {
return(
<View>
{this.contentBoolRender()}
</View>
);
}
}
const styles = StyleSheet.create({
login:{
padding: 20,
backgroundColor: 'white'
},
});
App.js
import React, {Component} from 'react';
import {
SafeAreaView,
StyleSheet,
ScrollView,
View,
Text,
StatusBar,
Button,
} from 'react-native';
import * as firebase from 'firebase';
import auth from '#react-native-firebase/auth';
import {
Header,
LearnMoreLinks,
Colors,
DebugInstructions,
ReloadInstructions,
} from 'react-native/Libraries/NewAppScreen';
import Notes from "./notes.js";
import CreateNote from "./createnote.js";
import Login from "./login.js";
class App extends Component {
state = {
loggedin: false,
notes: [
{
id: 1,
text: "mow the lawn",
author: "dean",
time: "10am"
},
{
id: 2,
text: "feed the dog",
author: "sam",
time: "2pm"
}
]
};
componentDidMount(){
const firebaseConfig = {
apiKey: 'AIzaSyABmRXh2nlBt4FtjfOWNaoz7q5Wy5pGFlc',
authDomain: 'familytodo-28018.firebaseapp.com'
}
firebase.initializeApp(firebaseConfig)
}
confirmLogin=()=>{
this.setState({loggedin:true})
}
updateNotes = (title, name, eventTime) => {
console.log("making new note");
let newNote = {
text: title,
author: name,
time: eventTime
};
this.setState(state => {
const list = state.notes.concat(newNote);
console.log(list);
return {
notes: list
};
});
};
deleteNotes = note => {
console.log("note deleted", note.id);
this.setState(state => {
var list = this.state.notes;
for (let i = 0; i < this.state.notes.length; i++) {
if (this.state.notes[i].id === note.id) {
list.pop(i);
}
}
return {
notes: list
};
});
};
conditionalRender=()=>{
if(this.state.loggedin===false){
return (
<View>
<Login confirmlogin = {this.confirmLogin} />
</View>
)
}
return(
<View>
<CreateNote
handleName={this.handleName}
handleEvent={this.handleEvent}
handleTime={this.handleTime}
updateNotes={this.updateNotes}
/>
<Notes style={styles.notes} notes={this.state.notes} deleteNotes={this.deleteNotes} />
</View>
);
}
render() {
return(
<View>
{this.conditionalRender()}
</View>
);
}
}
const styles = StyleSheet.create({
app: {
marginHorizontal: "auto",
maxWidth: 500
},
logo: {
height: 80
},
header: {
padding: 20
},
title: {
fontWeight: "bold",
fontSize: 15,
marginVertical: 10,
textAlign: "center"
},
notes:{
marginHorizontal: '50%'
},
text: {
lineHeight: 15,
fontSize: 11,
marginVertical: 11,
textAlign: "center"
},
link: {
color: "#1B95E0"
},
code: {
fontFamily: "monospace, monospace"
}
});
export default App;
any help would be appreciate greatly please help me provide better info if possible :)
I think this is happening because react-native has no exported member named Input. I think you are looking for either TextInput (from react-native) or Input (from react-native-elements which has a label prop)
For the TextInput, try changing the login component to this:
import React, {Component} from 'react';
import {ActivityIndicator, Button, TextInput, View} from 'react-native';
import * as firebase from 'firebase';
export default class Login extends Component {
state = {
email: '',
password: '',
authenticating: false
};
componentDidMount() {
const firebaseConfig = {
apiKey: 'garbagekey',
authDomain: 'garbage auth domain'
};
firebase.initializeApp(firebaseConfig);
}
onButtonPress = () => {
console.log("button pressed");
this.setState({authenticating: true});
};
contentBoolRender = () => {
if (this.state.authenticating === true) {
return (
<View>
<ActivityIndicator size="large"/>
</View>
);
}
return (
<View>
<TextInput
placeholder="Enter your Email..."
onChangeText={email => this.setState({email})}
value={this.state.email}
/>
<TextInput
placeholder="Enter your Password..."
onChangeText={password => this.setState({password})}
value={this.state.password}
secureTextEntry
/>
<Button title="login" onPress={() => this.onButtonPress()}/>
</View>
);
};
render() {
return (
<View>
{this.contentBoolRender()}
</View>
);
}
}
or for Input try using this:
import React, {Component} from 'react';
import {ActivityIndicator, Button, View} from 'react-native';
import { Input } from 'react-native-elements';
import * as firebase from 'firebase';
export default class Login extends Component {
state = {
email: '',
password: '',
authenticating: false
};
componentDidMount() {
const firebaseConfig = {
apiKey: 'garbagekey',
authDomain: 'garbage auth domain'
};
firebase.initializeApp(firebaseConfig);
}
onButtonPress = () => {
console.log("button pressed");
this.setState({authenticating: true});
};
contentBoolRender = () => {
if (this.state.authenticating === true) {
return (
<View>
<ActivityIndicator size="large"/>
</View>
);
}
return (
<View>
<Input
placeholder="Enter your Email..."
label = "Email"
onChangeText={email => this.setState({email})}
value={this.state.email}
/>
<Input
placeholder="Enter your Password..."
label = "Password"
onChangeText={password => this.setState({password})}
value={this.state.password}
secureTextEntry
/>
<Button title="login" onPress={() => this.onButtonPress()}/>
</View>
);
};
render() {
return (
<View>
{this.contentBoolRender()}
</View>
);
}
}
Additionally, have a look through the code above as your Login component had a few other typos including: secureTextEntry and onPress

Component for route must be a React component

I'm trying to make an app with React native and Expo. Im trying to make a navigation from my Profiel.js to ChoosePhoto.js. When im opening the app on my android emulator i'm getting the error "The component for route ProfielS must be a React component.
the navigator
import { createAppContainer } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';
import ProfielScreen from '../screens/Profiel';
import PhotoScreen from '../screens/ChoosePhoto';
const ProfielNavigator = createStackNavigator ({
ProfielS: ProfielScreen,
PhotoS: PhotoScreen
});
export default createAppContainer(ProfielNavigator);
my app.js
import React from 'react';
import { Text, View, StyleSheet, } from 'react-native';
import ProfielNavigator from './navigation/ProfielNavigator';
export default function App() {
return (
<ProfielNavigator />
);
};
my profiel.js
import React from 'react';
import { Text, View, StyleSheet, Button, Fragement } from 'react-native';
export class GebruikerScherm extends React.Component {
componentWillMount() {
this.getData();
}
constructor() {
super();
this.state = {
gebruikerId: 2,
currentPerson: {},
}
}
getData = () => {
return fetch('(my ip adress)/gebruiker/id?gebruikerId=' + this.state.gebruikerId, {
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
})
.then((response) => response.json())
.then((responseJson) => {
this.setState({ currentPerson: responseJson });
console.log(this.state.currentPerson);
})
.catch((error) => {
console.error(error);
});
}
render() {
return(
<View style={styles.container}>
<Text> Gebruiker: {this.state.currentPerson.gebruikerID} </Text>
<Text> Gebruiker: {this.state.currentPerson.gebruikerNaam} </Text>
<Text> Gebruiker: {this.state.currentPerson.biografie} </Text>
</View>
);
};
};
export const ProfielScreen = props =>{
return(
<View style={styles.container}>
<Button title="Profielfoto" onPress={() => {
props.navigation.navigate({
routeName: 'PhotoS'
});
}} />
</View>
);
};
const styles = StyleSheet.create({
container: {
marginTop: 200,
width: '100%',
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center'
}
});
Choosephoto.js
import React from 'react';
import { Text, View, StyleSheet, } from 'react-native';
const ChoosePhotoScreen = props =>{
return(
<View style={styles.container}>
<Button title="Profielfoto" onPress={() => {
props.navigation.navigate({
routeName: 'PhotoS'
});
}} />
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
export default ChoosePhotoScreen;
I expect my profiel.js page with a button. With the onpress action i want to go from profiel.js to choosephoto.js but the page wont even load.
You are wrong in the way you bring in objects.
The object you are trying to use is export only. Not export default
your profiel.js
export const ProfielScreen = props =>{
return(
<View style={styles.container}>
<Button title="Profielfoto" onPress={() => {
props.navigation.navigate({
routeName: 'PhotoS'
});
}} />
</View>
);
};
your Choosephoto.js
...
export default ChoosePhotoScreen;
Usage
import { ProfielScreen } from '../screens/Profiel';
import ChoosePhotoScreen as PhotoScreen from '../screens/ChoosePhoto';
...
const ProfielNavigator = createStackNavigator ({
ProfielS: ProfielScreen,
PhotoS: PhotoScreen
});
Example
import React from 'react'
This essentially says "find the default export from the react module and import that as a constant that I want to call React."
import { React } from 'react'
This says "find the export from the react module which is explicitly named React, and import that here as a constant that I want to call React."
in profiel.js add default keyword to export :
export default class GebruikerScherm extends React.Component {...
and also recheck all related paths in imports of screens.