I am having trouble posting data to an express backend with React Native via Android Emulator. The goal of the app is to allow customers to post microtask requests like home chores and lawn care where all the data will be stored to a AWS RDS MySQL Server. On the flip side there are freelancers who can view the customer posts through a feed. (For more background view here: https://askfavr.com) Now that you know the background onto the issue.
import React, { Component } from 'react';
import {
StyleSheet, Text, View, Image,
TextInput, KeyboardAvoidingView,
TouchableOpacity, AsyncStorage, ScrollView
} from "react-native";
export default class App extends React.Component {
state = {
request: {
C_Name: '', //this is a placeholder for the addRequest() method
Email: '',
Phone: '',
Category: '',
Time_Length: '',
Street: '',
City: '',
C_State: '',
Zip: '',
Finish_Before: '',
Price: '',
Details: ''
}
}
/* Just like getRequests, addRequest does exactly what its named as well. It adds a request
to the MySQL database following the initialization of the request state. The addRequest()
uses the post method which then returns are query string containing the new data submitted */
addRequest = _ => {
const { request } = this.state;
//query string set to remote server
fetch(`http://192.168.56.1:4000/requests/add?C_Name=${request.C_Name}&Email=${request.Email}&Phone=${request.Phone}&Category=${request.Category}&Time_Length=${request.Time_Length}&Street=${request.Street}&City=${request.City}&C_State=${request.C_State}&Zip=${request.Zip}&Finish_Before=${request.Finish_Before}&Price=${request.Price}&Details=${request.Details}`)
.catch(err => console.error(err))
}
render() {
const { request } = this.state; //set state for addRequest()
return (
<KeyboardAvoidingView behavior='padding' style={styles.wrapper}>
<Text style={styles.header}> Yardwork Request </Text>
<ScrollView>
<TextInput
style={styles.TextInput} placeholder='Name:' value={request.C_Name}
onChangeText={Name => this.setState(request.C_Name)}
underlineColorAndroid='black'
/>
<TextInput
style={styles.TextInput} placeholder='Email:' value={request.Email}
onChangeText={e => this.setState({ request: { ...request, Email: e.target.value } })}
underlineColorAndroid='black'
/>
<TextInput
style={styles.TextInput} placeholder='Phone:' value={request.Phone}
onChangeText={e => this.setState({ request: { ...request, Phone: e.target.value } })}
underlineColorAndroid='black'
/>
<TextInput
style={styles.TextInput} placeholder='Category:' value={request.Category}
onChangeText={e => this.setState({ request: { ...request, Category: e.target.value } })}
underlineColorAndroid='black'
/>
<TextInput
style={styles.TextInput} placeholder='Time of Job:' value={request.Time_Length}
onChangeText={e => this.setState({ request: { ...request, Time_Length: e.target.value } })}
underlineColorAndroid='black'
/>
<TextInput
style={styles.TextInput} placeholder='Street:' value={request.Street}
onChangeText={e => this.setState({ request: { ...request, Street: e.target.value } })}
underlineColorAndroid='black'
/>
<TextInput
style={styles.TextInput} placeholder='City:' value={request.City}
onChangeText={e => this.setState({ request: { ...request, City: e.target.value } })}
underlineColorAndroid='black'
/>
<TextInput
style={styles.TextInput} placeholder='State:' value={request.C_State}
onChangeText={e => this.setState({ request: { ...request, C_State: e.target.value } })}
underlineColorAndroid='black'
/>
<TextInput
style={styles.TextInput} placeholder='Zip:' value={request.Zip}
onChangeText={e => this.setState({ request: { ...request, Zip: e.target.value } })}
underlineColorAndroid='black'
/>
<TextInput
style={styles.TextInput} placeholder='Complete By:' value={request.Finish_Before}
onChangeText={e => this.setState({ request: { ...request, Finish_Before: e.target.value } })}
underlineColorAndroid='black'
/>
<TextInput
style={styles.TextInput} placeholder='Price:' value={request.Price}
onChangeText={e => this.setState({ request: { ...request, Price: e.target.value } })}
underlineColorAndroid='black'
/>
<TextInput
style={styles.TextInput} placeholder='Details:' value={request.Details}
onChangeText={e => this.setState({ request: { ...request, Details: e.target.value } })}
underlineColorAndroid='black'
/>
<TouchableOpacity
style={styles.btn}
onPress={this.addRequest}>
<Text> Request </Text>
</TouchableOpacity>
</ScrollView>
</KeyboardAvoidingView>
);
}
}
const styles = StyleSheet.create({
wrapper: {
flex: 1,
},
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#FFF',
paddingLeft: 40,
paddingRight: 40,
},
header: {
fontSize: 24,
marginTop: 25,
color: '#000000',
fontWeight: 'bold',
},
TextInput: {
alignSelf: 'stretch',
padding: 16,
marginBottom: 20,
borderRadius: 12,
color: '#000000',
fontSize: 16,
//backgroundColor: '#fff',
},
btn: {
alignSelf: 'stretch',
backgroundColor: 'green',
padding: 20,
borderRadius: 12,
alignItems: 'center',
},
small: {
fontSize: 15,
color: '#000000',
paddingTop: 10,
},
});
when I try to run essentially the same thing in react native I get this error
setState(...) takes an object of state variables to update or a function which returns an object of state variables
but in Plain React I can use nearly the exact code with no problem and post data easily
import React, { Component } from 'react';
import './App.css';
class App extends Component {
state = {
requests: [], //null state for the getRequests() method
request: {
C_Name: '', //this is a placeholder for the addRequest() method
Email: '',
Phone: '' ,
Category: '',
Time_Length:'' ,
Street:'' ,
City:'' ,
C_State:'' ,
Zip:'' ,
Finish_Before:'' ,
Price: '',
Details: ''
}
}
/* Mounts the "getRequests" to display on the screen, instead of writing the
full method within the componentDidMount()
componentDidMount() Purpose: this method takes place before rendering to
essentially change the state of the arrays and variables if they are no
longer null. */
componentDidMount() {
this.getRequests();
}
getRequests = _ => {
fetch('http://192.168.56.1:4000/requests')
.then( response => response.json())
.then(response => this.setState({ requests: response.data}))
.catch( err => console.error(err))
}
/* Just like getRequests, addRequest does exactly what its named as well. It adds a request
to the MySQL database following the initialization of the request state. The addRequest()
uses the post method which then returns are query string containing the new data submitted */
addRequest =_ => {
const { request } = this.state;
//query string set to remote server
fetch(`http://localhost:4000/requests/add?C_Name=${request.C_Name}&Email=${request.Email}&Phone=${request.Phone}&Category=${request.Category}&Time_Length=${request.Time_Length}&Street=${request.Street}&City=${request.City}&C_State=${request.C_State}&Zip=${request.Zip}&Finish_Before=${request.Finish_Before}&Price=${request.Price}&Details=${request.Details}`)
.then(this.getRequests)
.catch(err => console.error(err))
}
//Fields of Data for a FAVR Request:
//idyard_record, time_posted, C_Name, Email, Phone, Category, Time_Length, Street, City, C_State, Zip, Finish_Before, Price
//Details, RequestID, Proposals
renderRequest = ({ idyard_record, C_Name, Category }) =>
<div key={idyard_record}>{C_Name}: <b>{Category} </b><br/><br/> </div> //displays all requests from the MySQL data similar to a flatlist
render() {
const { requests, request} = this.state; //set state for getRequests() && getRequest()
const mainDiv = {
align: 'center',
justifyContent: 'center',
flex: '1',
margin: '2%'
}
const divStyle = {
margin: '2%',
};
const inputBorder = {
borderColor: 'lightgrey',
padding: '5px',
marginTop: '1%',
marginLeft: '1%'
}
return (
<div className="App" style={mainDiv} >
{requests.map(this.renderRequest)}
<div>
<div style={divStyle} >
<label style={{align: 'left'}} > Name: </label>
<input style={inputBorder} value={request.C_Name}
onChange={e => this.setState({ request: {...request, C_Name: e.target.value}})} />
</div>
<div style={divStyle} >
<label> Email: </label>
<input style={inputBorder} value={request.Email}
onChange={e => this.setState({ request: {...request, Email: e.target.value}})} />
</div>
<div style={divStyle} >
<label style={{textAlign: 'left'}} > Phone: </label>
<input style={inputBorder} value={request.Phone}
onChange={e => this.setState({ request: {...request, Phone: e.target.value}})} />
</div>
<div style={divStyle} >
<label> Category: </label>
<input style={inputBorder} value={request.Category}
onChange={e => this.setState({ request: {...request, Category: e.target.value}})} />
</div>
<div style={divStyle} >
<label> Time of Job: </label>
<input style={inputBorder} value={request.Time_Length}
onChange={e => this.setState({ request: {...request, Time_Length: e.target.value}})} />
</div>
<div style={divStyle} >
<label> Street: </label>
<input style={inputBorder} value={request.Street}
onChange={e => this.setState({ request: {...request, Street: e.target.value}})} />
</div>
<div style={divStyle} >
<label> City: </label>
<input style={inputBorder} value={request.City}
onChange={e => this.setState({ request: {...request, City: e.target.value}})} />
</div>
<div style={divStyle} >
<label> State: </label>
<input style={inputBorder} value={request.C_State}
onChange={e => this.setState({ request: {...request, C_State: e.target.value}})} />
</div>
<div style={divStyle} >
<label> Zip: </label>
<input style={inputBorder} value={request.Zip} placeholder='55901'
onChange={e => this.setState({ request: {...request, Zip: e.target.value}})} />
</div>
<div style={divStyle} >
<label> Complete By: </label>
<input type="datetime-local" style={inputBorder} value={request.Finish_Before} placeholder='55901'
onChange={e => this.setState({ request: {...request, Finish_Before: e.target.value}})} />
</div>
<div style={divStyle} >
<label> Price: </label>
$<input type="number" style={inputBorder} value={request.Price} placeholder='$20'
onChange={e => this.setState({ request: { ...request, Price: e.target.value }})} />
</div>
<div style={divStyle} >
<label> Details: </label>
<textarea rows={3} style={inputBorder} value={request.Details}
onChange={e => this.setState({ request: { ...request, Details: e.target.value }})} />
</div>
<button onClick={this.addRequest}> Request FAVR </button>
</div>
</div>
);
}
}
export default App;
Does anyone have suggestions to resolve this issue? I know the backend isn't the issue because the plain react app can post to it, and the emulator/plain react app can display the data from the MySQL DB with no issue.
The problematic one seems to be this one:
onChangeText={Name => this.setState(request.C_Name)}
This line is in the React Native code, but not the plain React code, so that's the difference between the two. You should be passing setState()
an object, something like:
this.setState({ request: {...request, C_Name: e.target.value}})
similar to what you do for the other ones.