React, GraphQL, Apollo add data to the database via form - javascript

I have setup basic the GraphQL Playground and am able to query or add objects which in my case are cars. I am even able to query cars and display them on front end but I am having issues in terms of adding or updating the database via GraphQL by entering data in to a form. I am using the use state hook and as soon as I add a use state hook the page stops loading and I come up with a blank page as in it stops loading:
The code is below:
export default function CarForm() {
const [formState, setFormState] = useState({
name: '',
mileage: '',
dailyPrice: '',
monthlyPrice: '',
gas: '',
gearType: '',
thumbnailUrl: ''
})
const [carForm] = useMutation(ADD_NEW_CAR, {
variables: {
name: formState.name,
mileage: formState.mileage,
dailyPrice: formState.dailyPrice,
monthlyPrice: formState.monthlyPrice,
gas: formState.gas,
gearType: formState.gearType
}
});
return (
<div>
<h1>
Submit your car
</h1>
<Form>
<h5 >make and model of car :
<input className="field" type="text" value={formState.name}
onChange={(e) =>
setFormState({
...formState,
name: e.target.value
})
} />
</h5>
<h5>
Mileage
<input className="field" type="text" value={formState.mileage}
onChange={(e) =>
setFormState({
...formState,
mileage: e.target.value
})
} />
</h5>
<h5>gearType
<input className="field" type="text" value={formState.gearType}
onChange={(e) =>
setFormState({
...formState,
gearType: e.target.value
})
} />
</h5>
<h5>gas
<input className="field" type="text" value={formState.gas}
onChange={(e) =>
setFormState({
...formState,
gas: e.target.value
})
} />
</h5>
<h5>dailyPrice
<input className="field" type="text" value={formState.dailyPrice}
onChange={(e) =>
setFormState({
...formState,
dailyPrice: e.target.value
})
} />
</h5>
<h5>monthlyPrice
<input className="field" type="text" value={formState.monthlyPrice}
onChange={(e) =>
setFormState({
...formState,
monthlyPrice: e.target.value
})
} />
</h5>
<h5>thumbnailUrl
<input className="field " type="text" value={formState.thumbnailUrl}
onChange={(e) =>
setFormState({
...formState,
thumbnailUrl: e.target.value
})
} />
</h5>
</Form>
<Button onSubmit={(e) => {
e.preventDefault();
}}>
submit
</Button>
</div >
);
}```
I am able to use the mutation or query via the GraphQL playground but am not able to update the database via adding data to the form. it just returns a blank page. What am I doing wrong here? Is there an easier way to input data?
I wanna add the data of the cars via the form but it returns a blank page.

In the onSubmit callback you need to actually call the carForm function, passing the variables there. Just leave the useMutation with one param, and add the variables in the submit handler. Check out this pseudo-code:
const [carForm] = useMutation(ADD_NEW_CAR)
const submitHandler = async (e) => {
e.preventDefault();
await carForm({
variables: {...} // useState variables.
});
}
return <Form>
...
<Button onSubmit={submitHandler}>Submit</Button>
</Form>

Related

random number not changing on submit in React form

I have built a travel journal however I ran into two big bugs, one of them where the id which is set to Math.random()*10000 and is expected to change on submit however it does not, another issue I have is where once I remove one journal entry, I am not able to add any more entries via submit.
I have tried adding the math.random in different places however it doesn't change, I have run out of ideas on how to tackle this issue, if you have any suggestions ,any help is appreciated.
import React, { useState } from "react";
import Card from "./Card";
import data from "./data";
function Entry(props) {
const [entry, setEntry] = useState([
{
title: "",
location: "",
googleMapsUrl: "",
startDate: "",
endDate: "",
description: "",
imageUrl: "",
id: Math.random() * 100000000,
},
]);
function handleChange(e) {
setEntry((prevState) => {
return {
...prevState,
[e.target.name]: e.target.value,
};
});
}
// const newData = [...data];
function handleSubmit(e) {
e.preventDefault();
setEntry((prevState) => {
return {
...prevState,
};
});
data.unshift(entry);
}
return (
<div>
<form className="entry-form">
<h1 className="entry-title">Add another Travel Memory</h1>
<div className="journal-entry">
<input
className="entry-input"
type="text"
value={entry.location}
name="location"
placeholder="LOCATION"
onChange={handleChange}
required
/>
<input
className="entry-input"
type="text"
name="title"
value={entry.title}
placeholder="LANDMARK"
onChange={handleChange}
required
/>
<input
className="entry-input"
type="text"
name="googleMapsUrl"
value={entry.googleMapsUrl}
placeholder="GOOGLE MAPS LINK"
onChange={handleChange}
required
/>
<input
className="entry-input"
type="date"
value={entry.startDate}
name="startDate"
onChange={handleChange}
required
/>
<input
className="entry-input"
type="date"
value={entry.endDate}
name="endDate"
onChange={handleChange}
required
/>
<textarea
className="entry-input"
placeholder="ADD YOUR STORY OR A FUN FACT FROM YOUR JOURNEY"
name="description"
value={entry.description}
onChange={handleChange}
required
/>
<input
className="entry-input"
type="text"
name="imageUrl"
value={entry.imageUrl}
placeholder="ADD A IMAGE LINK TO REMIND YOU OF YOUR TRAVEL"
onChange={handleChange}
/>
<button type="submit" onClick={handleSubmit} className="entry-btn">
add your travel memory
</button>
</div>
</form>
<Card data={data} />
</div>
);
}
export default Entry;
Math.random()*10000 and is expected to change on submit however it does not
Because no code was written to change it. Take a look at the state update in the submit handler:
setEntry((prevState) => {
return {
...prevState,
};
});
No values are changed. The new state is an exact copy of the previous state. Contrast this with the state update in the change handler for the input fields:
setEntry((prevState) => {
return {
...prevState,
[e.target.name]: e.target.value,
};
});
Notice how the new state is constructed from the previous state, and a given field is updated.
If you want to update the id field in the submit handler, update the id field in the submit handler:
setEntry((prevState) => {
return {
...prevState,
id: Math.random() * 100000000
};
});

React Context Updates Not Firing During OnSubmit Functions?

I am using the Context API to add user details from a form to a global state. When I submit the form, the state is always "one step behind" - essentially, a double click is required to get the desired result.
Basic recreation of the code (have removed irrelevant bits and some imports):
import { UserProvider, UserContext } from "../../StateContext"
export default function SignUp() {
const user = useContext(UserContext)
const history = useHistory()
const handleSubmit = (e) => {
e.preventDefault()
user.setName(userDetails.name)
//logging out the user object here will result in the previous values shown
}
const [userDetails, setUserDetails] = useState({
name: null,
age: null,
})
return (
<>
<form onSubmit={handleSubmit}>
<div className="form-vertical-batch">
<FormControl>
<Input
type="text"
placeholder="Your Name"
required={true}
onChange={(e) =>
setUserDetails({ ...userDetails, name: e.target.value })
}
></Input>
<FormHelperText>
Put the name you're best known by online - either a nickname,
brand name, or your real name.
</FormHelperText>
</FormControl>
<FormControl>
<TextField
type="number"
inputProps={{ min: 18, max: 99 }}
onChange={(e) =>
setUserDetails({ ...userDetails, age: e.target.value })
}
/>
<FormHelperText>
You currently must be at least 18 years old to use the platform.
</FormHelperText>
</FormControl>
</div>
</div>
<input
id="formButton"
className="btn sign-up-button"
type="submit"
placeholder="Send message"
/>
</form>
</>
)
}
To clarify the issue here - if I submit with a name as "Reikon" and log our the user object, the first time it will return as null, and then the second time it will return "Reikon" as expected.

How to clear controlled forms in react-redux

I'm trying to clear a form in my react-redux component. I know that I should be able to clear them using setState() after a submit, but since I'm receiving all my data as props (via the redux store) is there an easy way to do this within the component itself?
class Postform extends Component {
constructor(props){
super(props)
this.state={
propertyName: ' enter name ',
footage: ' size in sqft ',
address: ' full address ',
price: ' $ 00.00 '
}
}
onChange =(e)=>{
this.setState({ [e.target.name] :e.target.value});
}
onSubmit = (e) =>{
e.preventDefault()
const newListing = {
propertyName: this.state.propertyName,
footage: this.state.footage,
address: this.state.address,
price: this.state.price
}
this.props.newProperty(newListing)
// my attempt to reset the state of the form (unsure how to accomplish this?)
this.setState({
propertyName: '',
footage: '',
address: '',
price: ''
})
};
render() {
return (
<div className="form">
<h2>Add Listing</h2>
<form onSubmit = {this.onSubmit}>
<div>
<label>your listing name</label><br/>
<input name="propertyName" type="text" onChange={this.onChange} placeholder={this.state.propertyName} />
</div>
<div>
<label>listing size </label><br/>
<input name="footage" onChange={this.onChange} placeholder={this.state.footage} />
</div>
<div>
<label>listing location </label><br/>
<input name="address" onChange={this.onChange} placeholder={this.state.address} />
</div>
<div>
<label>desired price </label><br/>
<input name="price" onChange={this.onChange} placeholder={this.state.price} />
</div>
<br/>
<button className="submitbtn" type="submit">Submit</button>
</form>
</div>
)
}
}
Postform.propTypes = {
newProperty: PropTypes.func.isRequired,
new: PropTypes.object
}
const mapStateToProps = state =>({
listings: state.listings.properties,
new: state.listings.newListing
});
export default connect(mapStateToProps, {newProperty})(Postform)
I checked around online and found a few solutions. I wanted to see if anyone could tell me based on my code if there would be a preferred way of achieving this?
Here all the different methods I found not sure which I should use based on my component though : https://redux-form.com/6.0.0-alpha.7/docs/faq/howtoclear.md/
Your approach seems valid to me, I would only do the job in a bit 'lazy' manner:
this.setState(Object.keys(this.state).forEach(key => this.state[key] = ''))
import { initialize, reset } from 'redux-form';
dispatch(initialize('formName', {})); // Clear form
// or
dispatch(reset('formName'));

add multiple input lines and add it to fetch method with reactJS

I want to add some input lines by a click of a button and add it to state so I can send it to the server, but I'm not sure how to add it to the fetch method or even if it's added to state,
this is what i have so far:
export class AdminPage extends React.Component {
constructor(props){
super(props);
this.state = {
sendeEmail: '',
matrialeliste: [{
matrialer: '',
antal: '',
pris: ''}]
};
}
handleUserInput = (e) => {
if (["matrialer", "antal", "pris"].includes(e.target.className) ) {
let matrialeliste = [...this.state.matrialeliste]
//matrialeliste[e.target.dataset.id][e.target.className] = e.target.value
this.setState({ matrialeliste }, () => console.log(this.state.matrialeliste))
} else {
const name = e.target.name;
const value = e.target.value;
this.setState({[name]: value};
}
}
addMatrialeliste = (e) => {
this.setState((prevState) => ({
matrialeliste: [...prevState.matrialeliste, {matrialer:"", antal:"", pris:""}],
}));
}
onSubmitSignIn = (event) => {
event.preventDefault();
fetch(`${api.url}/form`, {
method: 'post',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
sendeEmail: this.state.sendeEmail,
})
})
.then((response) => (response.json()))
.catch(error => console.log(error));
}
render(){
let {matrialeliste} = this.state;
return(
<div>
<div>
<h1>Arbejds seddel</h1>
<form>
<div>
<button type="button" onClick={this.addMatrialeliste}>
tilføj materialer
</button>
{
matrialeliste.map((val, idx) => {
return(
<div key={idx}>
<div>
<label htmlFor="matrialer">
Matrialeliste
</label>
<input name='matrialer' type="text" className='matrialer' onChange={this.handleUserInput} />
</div>
<div>
<label htmlFor="antal">
Antal
</label>
<input name='antal' type="number" className='antal' onChange={this.handleUserInput} />
</div>
<div>
<label htmlFor="pris">
Pris
</label>
<input name='pris' type="number" className='pris' onChange={this.handleUserInput} />
</div>
</div>)})}
<label htmlFor="email">
E-mail
</label>
<input name='email' type="email" onChange={e => this.handleUserInput} />
<button type="submit">Send som E-mail</button>
<div>
<button type="submit" disabled=this.state.formValid}>Create</button>
</div>
</div>
</form>
</div>
</div>
);
}
}
I can get to add extra lines, but I don't know how to add it to the fetch method.
I was thinking I could map it, but I'm still unsure how do that
Creating forms with plain React requires you to write each part of the process and for a complex state its become tough .so, my personal opinion is to go with Formik or React Hook Form as they cover most of the features.
In your case, I am assuming you want to sent whole state to fetch method .here is an example of your code which implemented with Formik library.

Unable to type into React input field

I am unable to type any input into my input field. I am using React, and have already set a handleChange and a handleSubmit function. The first two input fields, for 'name' and 'email', take input just fine. But for 'favoriteCity', it doesn't seem to work.
I am wondering if it is due to a MongoDB error that I am getting.
class UserPage extends Component {
state = {
user: [],
newUser: {
name: '',
email: '',
favoriteCity: ''
}
}
getAllUsers = () => {
axios.get('/api/users')
.then(res => {
this.setState({ user: res.data })
})
}
componentDidMount() {
this.getAllUsers()
}
handleChange = event => {
const newUser = { ...this.state.newUser };
newUser[event.target.name] = event.target.value;
this.setState({ newUser: newUser});
}
handleSubmit = event => {
event.preventDefault()
axios.post('/api/users', this.state.newUser)
.then(res => {
this.props.history.push(`/users/${res.data._id}`)
})
}
render() {
return (
<div>
{ /* This shows a list of All Users */ }
{this.state.user.map(user => (
<div key={user._id}>
<Link to={`/users/${user._id}`}>{user.name}</Link>
</div>
))}
<h1>New User Page</h1>
<form onSubmit={this.handleSubmit}>
<label>Name: </label>
<input
type="text"
name="name"
placeholder="Name?"
value={this.state.newUser.name}
onChange={this.handleChange}
/>
<label>Email: </label>
<input
type="text"
name="email"
placeholder="Email?"
value={this.state.newUser.email}
onChange={this.handleChange}
/>
<label>Favorite City: </label>
<input
type="text"
name="city"
placeholder="Favorite City?"
value={this.state.newUser.favoriteCity}
onChange={this.handleChange}
/>
<Button
type="submit"
value="Submit"
variant="contained"
color="primary"
>
Create User
</Button>
</form>
</div>
);
}
}
export default UserPage;
Please help.
Weird that email works fine, from what you posted your handleChange function is only updating the name on the newUser.
What you should see is what you type in all the inputs appear in the name input.
To fix this, you should probably have separate change handlers for each input:
handleNameChange
handleEmailChange
...
You should also consider storing name, email etc.. at the root of your state instead of nesting them in an object, that'll simplify the handler functions code.

Categories

Resources