How to pass input value to another react component - reactjs

I'm making a react project for practice, where I have multiple forms, distributed across multiple pages and I'm using react components for each page with the help of react routing. I have a submit page in the end where the user is able to press the button and I need all the form values from previous pages so that I can use it as parameters to POST it on a REST API. Since I'm new to react, I'm having a hard time figuring out how to pass all these data to this submit page component, any help or advice would be appreciated!
This is one component for one of the pages, for instance :
Personal.jsx
function Personal(){
const text = "You watch “What? Where? When?” Yeah. Our founders used to play it. That’s where they got a question about a famous American author and screenwriter Ray Bradbury. Albeit, our CEO Gaga Darsalia forgot the exact name and he answered Ray Redberry. And at that moment, a name for a yet to be born company was inspired - Redberry 😇"
const [fName, setfName] = useState("");
const [lName, setlName] = useState("");
const [email, setEmail] = useState("");
const [phone, setPhone] = useState("");
return (
<div className="personal-container">
<div className="leftDiv">
<h1 className="coordinates-h1">Hey, Rocketeer, what are your coordinates?</h1>
<div className="inputDiv">
<form>
<Input value={fName} type="text" onChange={(e) => setfName(e.target.value)} required placeholder="First Name"/>
<Input value={lName} type="text" onChange={(e) => setlName(e.target.value)} required placeholder="Last Name"/>
<Input value={email} type="email" onChange={(e) => setEmail(e.target.value)} required placeholder="E Mail"/>
<Input value={phone} onChange={(e) => setPhone(e.target.value)} pattern="[5]{1}[0-9]{2}[0-9]{2}[0-9]{2}[0-9]{2}" type="tel" placeholder="+995 5_ _ _ _"/>
</form>
</div>
<div>
<PersonalSVG />
</div>
</div>
<div className="rightDiv">
<h1 className="origins-h1">Redberry Origins</h1>
<p className="origins-p">{text}</p>
</div>
</div>
)
}
export default Personal;
I need to pass these input values to the submit page : Submit.jsx :
function Submit(){
const style = {
color:"white",
textDecoration : "none"
}
const onSubmit = (e) => {
console.log("submitted");
const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
"token": "76977183-c0e1-4f49-b51d-34e590260b10",
"first_name": "gela",
"last_name": "gelashvili",
"email": "gelashvili#gela.ge",
"phone": "+995591933382",
"skills": [
{
"id": 1,
"experience": 3
}
],
"work_preference": "from_home",
"had_covid": true,
"had_covid_at": "2022-02-23",
"vaccinated": true,
"vaccinated_at": "2022-02-23",
"will_organize_devtalk": true,
"devtalk_topic": "I would ...",
"something_special": "I am special!"
})
};
fetch('https://bootcamp-2022.devtest.ge/api/application', requestOptions)
}
return (
<div className="submitDiv">
<Link style={style} to="/thanks"><button onClick={onSubmit} className="submitButton">Submit</button></Link>
<div><a><Link style={style} to="/about"><h2>go back</h2></Link></a></div>
</div>
)
}
export default Submit;
I'm looking for replacing the custom strings in the post body, with actual input values. Thanks in advance

Related

React UI/dom is not updating after data insertion in json-server

I am learning React from few days and I am trying to learn Axios, Everything worked fine until I tried to insert data, which I successfully inserted but My React Page did not updated contact list immediately.
HERE's MY CODE:
App.js
import Axios from "axios";
import React, { useEffect, useState } from "react";
import Add__Contact from "./api/Add__Contact";
const App = () => {
const [name, setName] = useState("");
const [phone, setPhone] = useState("");
const [contacts, setContacts] = useState([]);
const url = "http://localhost:3006/contacts";
//get all availbale contacts
useEffect(() => {
// get all contacts async
async function getUsers() {
Axios.get(url).then((response) => {
setContacts(response.data);
});
}
getUsers();
console.log(contacts);
// get all contacts non-async
// Axios.get(url).then((response) => {
// setContacts(response.data);
// });
}, []);
//add new contact to server
const addContact = () => {
const saveRes = Add__Contact({ name, phone });
};
// view
return (
<div>
<h4>Add contact</h4>
<div>
<input type="text" name="name" value={name} onChange={(e) => setName(e.target.value)} placeholder="name here" />
<br />
<br />
<input
type="text"
name="phone"
value={phone}
onChange={(e) => setPhone(e.target.value)}
placeholder="Phone here"
/>
<br />
<br />
<button onClick={addContact}>Add to Contact</button>
</div>
<hr />
<h4>List of Contacts</h4>
<div>
{contacts.map((contact) => {
return (
<div key={contact.id}>
<span>{contact.name} : </span>
<span> {contact.phone}</span>
</div>
);
})}
</div>
</div>
);
};
export default App;
Add__Contact.js
import Axios from "axios";
const Add__Contact = async ({ name, phone }) => {
Axios({
method: "post",
url: "http://localhost:3006/contacts",
headers: {
"Content-Type": "application/json",
},
data: {
name,
phone,
},
}).then(function (res) {
// console.log(res);
});
};
export default Add__Contact;
db.json
{
"contacts": [
{
"name": "Max",
"phone": "123456",
"id": 1
},
{
"name": "John",
"phone": "13454",
"id": 2
},
{
"name": "Candy",
"phone": "1245781245",
"id": 3
}
]
}
I am not sure why it's not updating list automatically, I thought useEffect will run everytime I click and call Add__Contact(). Can you please tell me what did i missed or doing wrong?
I am not sure if useEffect hook is good for what I want to achieve or not, so please guide me. Thank you in advance.
data insertion is working fine, but after I insert it, it's not updating ui, even if I am fetching data inside useEffect
Your useEffect hook is only ran once - when the component mounts. This is because you have given it an empty dependency array (the 2nd argument).
The dependency array determines when the effect function will run. If its empty, it will only run when the component is mounted (displayed for the very first time). If you add something in the array, the effect will run on mount, and whenever the provided value changes.
In your case, you have an event (the click event from the Add to Contacts button) after which you want your data to be fetched again. But you also want to fetch data when the page loads.
One way to do it is something like this:
const Add__Contact = async ({ name, phone }) => {
// Return the Promise returned from the Axios call
return Axios({
method: "post",
url: "http://localhost:3006/contacts",
headers: {
"Content-Type": "application/json",
},
data: {
name,
phone,
},
});
};
const App = () => {
const [name, setName] = useState("");
const [phone, setPhone] = useState("");
const [contacts, setContacts] = useState([]);
const url = "http://localhost:3006/contacts";
// Add a function to fetch contacts
const fetchContacts = async () => {
const res = await Axios.get(url);
setContacts(res.data);
};
// Effect that fetches contacts when the component loads
useEffect(() => {
fetchContacts();
}, []);
//add new contact to server
const addContact = async () => {
// await the Promise returned
const saveRes = await Add__Contact({ name, phone });
// Fetch the contacts list again
await fetchContacts();
};
// view
return (
<div>
<h4>Add contact</h4>
<div>
<input type="text" name="name" value={name} onChange={(e) => setName(e.target.value)} placeholder="name here" />
<br />
<br />
<input
type="text"
name="phone"
value={phone}
onChange={(e) => setPhone(e.target.value)}
placeholder="Phone here"
/>
<br />
<br />
<button onClick={addContact}>Add to Contact</button>
</div>
<hr />
<h4>List of Contacts</h4>
<div>
{contacts.map((contact) => {
return (
<div key={contact.id}>
<span>{contact.name} : </span>
<span> {contact.phone}</span>
</div>
);
})}
</div>
</div>
);
};
So you'r Contacts Array is not updated .Even you got a data from axios call .
Like if axios is returning data then i think you'r state in not updating then you have to use
setContacts((prv)=>[...prv,...res.data])
If you'r facing problem on Add time . Then make a separate function then use that in useEffect() && your ADD_Contact() .
const App = () => {
const [name, setName] = useState("");
const [phone, setPhone] = useState("");
const [contacts, setContacts] = useState([]);
const getContacts = async () => {
const res = await Axios.get('http://localhost:3006/contacts');
setContacts(res.data);
};
useEffect(() => {
getContacts();
}, []);
const addContact = async () => {
const saveRes = await Add__Contact({ name, phone });
await getContacts();
};
return (
<div>
<h4>Add contact</h4>
<div>
<input type="text" name="name" value={name} onChange={(e) => setName(e.target.value)} placeholder="name here" />
<br />
<br />
<input
type="text"
name="phone"
value={phone}
onChange={(e) => setPhone(e.target.value)}
placeholder="Phone here"
/>
<br />
<br />
<button onClick={addContact}>Add to Contact</button>
</div>
<hr />
<h4>List of Contacts</h4>
<div>
{contacts.map((contact) => {
return (
<div key={contact.id}>
<span>{contact.name} : </span>
<span> {contact.phone}</span>
</div>
);
})}
</div>
</div>
);
};

React form not rendering with selectedRow data

I am new to React.js so forgive me if this is an obvious mistake. I have a list of data with an update button on each row and it is supposed to open a form with the relevant fields already populated with the selectedRow.data but the controls are blank. The URL in Postman is giving the right response so that's not the problem. Any help would be appreciated.
Also getting this error in my console:
"Warning: A component is changing a controlled input to be uncontrolled. This is likely caused by the value changing from a defined to undefined, which should not happen. Decide between using a controlled or uncontrolled input element for the lifetime of the component"
Here is my code:
import React, { useState, useContext, useEffect } from "react";
import { useParams, useNavigate } from "react-router-dom";
import { AppContext } from '../context/AppContext';
import AdminPortal from '../apis/AdminPortal'
const OrganizationUpdateForm = (props) => {
const {id} = useParams()
const { organizations } = useContext(AppContext);
const [name, setName] = useState("");
const [shortName, setShortName] = useState("");
const [parentOrg, setParentOrg] = useState("");
const [website, setWebsite] = useState("");
const [comments, setComments] = useState("");
useEffect(() => {
async function fetchData () {
const response = await AdminPortal.get(`organizations/${id}`);
console.log(response.data.data);
setName(response.data.data.organizations.name);
setShortName(response.data.data.organizations.short_name);
setParentOrg(response.data.data.organizations.parent_org);
setWebsite(response.data.data.organizations.website);
setComments(response.data.data.organizations.comments);
};
fetchData();
}, []);
let Navigate = useNavigate();
const handleSubmit = async (e) => {
e.preventDefault();
const updateOrganization = await AdminPortal.put(`organizations/${id}`, {
name,
short_name: shortName,
parent_org: parentOrg,
website,
comments
});
Navigate("/");
};
return (
<div>
<form action=''>
<div className="form-group">
<label htmlFor='name'>Name</label>
<input
value={name}
onChange={(e) => setName(e.target.value)}
id="name"
className="form-control"
type="text"
/>
</div>
<div className="form-group">
<label htmlFor='short_name'>Short Name</label>
<input
value={shortName}
onChange={(e) => setShortName(e.target.value)}
id="name"
className="form-control"
type="text"
/>
</div>
<div className="form-group">
<label htmlFor='parent_org'>Parent Organization</label>
<input
value={parentOrg}
onChange={(e) => setParentOrg(e.target.value)}
id="name"
className="form-control"
type="text"
/>
</div>
<div className="form-group">
<label htmlFor='website'>Website</label>
<input
value={website}
onChange={(e) => setWebsite(e.target.value)}
id="name"
className="form-control"
type="text"
/>
</div>
<div className="form-group">
<label htmlFor='comments'>Comments</label>
<input
value={comments}
onChange={(e) => setComments(e.target.value)}
id="name"
className="form-control"
type="text"
/>
</div>
{/* <button
type="submit"
onClick={handleSubmit}
className="btn btn-primary"
>
Submit
</button> */}
</form>
</div>
)
}
export default OrganizationUpdateForm
{
"status": "success",
"results": 1,
"data": {
"organizations": [
{
"id": 20,
"name": "International Aids Vaccine Initiative",
"name_localized": "IAVI",
"parent_org_id": null,
"website": "",
"comment": "",
"create_date": "2019-08-26T12:42:49.457Z",
"logo": null,
"short_name": "IAVI"
}
]
}
}
Above is the response when I hit the API with "http://localhost:3000/api/v1/organizations/20" which is the correct response. Below is the code for AdminPortal
import axios from "axios";
export default axios.create({
baseURL: "http://localhost:3000/api/v1/"
})
This is a screen capture of the network response
The last line in the {id} has no response and I'm wondering if that might be a clue and I'm also surprise to see the port change from 3001 to 3000. I did change to response.data.organizations which seems to match with the structure in the response but that didn't make a difference. Here is what I changed:
useEffect(() => {
async function fetchData () {
// const response = await AdminPortal.get(`organizations/${id}`);
const response = await AdminPortal.get(`organizations/${id}`);
console.log(response.dataorganizations);
setName(response.data.organizations.name);
setShortName(response.data.organizations.short_name);
setParentOrg(response.data.organizations.parent_org);
setWebsite(response.data.organizations.website);
setComments(response.data.organizations.comments);
};
fetchData();
}, []);
Thanks for your support.

React UseState hook for updating data - CRUD

Im just wondering if anyone could point out where im going wrong with my code.
Im relativly new to react so began with a simple todo list.
I then edited this to allow for various other forms such as menu, profile etc.
Below is the code attached for the menu section.
My back end works if I use postmaster which leads me to believe its my front end, and specifically my useState.
I can call the data and view it within my modal and it appears, however, I cant seem to edit the specific data within the form field and/or post it to my database.
Any help would be greatly appreciated.
Ive attached my code below.
import React, { Fragment, useState } from "react";
const EditMenu = ({ menu }) => {
//editText function
const [inputs, setInputs] = useState(menu.item_title, menu.item_price, menu.item_description, menu.item_category);
const { title, category, price, description } = inputs;
const onChange = e =>
setInputs({ ...inputs, [e.target.name]: e.target.value });
const editMenuItem = async (item_id) => {
try {
const body = { title, category, price, description };
const res = await fetch(`http://localhost:5000/menu/${item_id}`, {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body)
});
window.location = "/admin";
} catch (error) {
console.error(error.message);
}
};
return (
<Fragment>
<button type="button" className="btn btn-warning" data-toggle="modal" data-target={`#id${menu.item_id}`}>Edit</button>
{/*id = "id21"*/}
<div className="modal" id={`id${menu.item_id}`} onClick={() => setInputs(menu.item_title, menu.item_price, menu.item_description, menu.item_category)}>
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-header">
<h4 className="modal-title">Edit Menu</h4>
<button className="close btn-danger" data-dismiss="modal" onClick={() => setInputs(menu.item_title, menu.item_price, menu.item_description, menu.item_category)}>×</button>
</div>
<div className="modal-body">
<input type="text" name="title" placeholder="Title" className="form-control my-3" value={menu.item_title} onChange={e => onChange(e)} />
<input type="tel" name="price" placeholder="Price" className="form-control my-3" value={menu.item_price} onChange={e => onChange(e)} />
<input type="text" name="description" placeholder="Description" className="form-control my-3" value={menu.item_description} onChange={e => onChange(e)} />
<input type="text" name="category" placeholder="Category" className="form-control my-3" value={menu.item_category} onChange={e => onChange(e)} />
</div>
<div className="modal-footer">
<button type="button" className="btn btn-warning" data-dismiss="modal" onClick={() => editMenuItem(menu.item_id)}>Edit</button>
<button type="button" className="btn btn-danger" data-dismiss="modal" onClick={() => setInputs(menu.item_title, menu.item_price, menu.item_description, menu.item_category)}>Close</button>
</div>
</div>
</div>
</div>
</Fragment>
);
};
Update,
Ive tried various suggested fixes using the below answers so far.
Both of these fixes allow the form fields to be editable, and the information within the form fields changes and thus within the state also however it is not sent to the database. Upon refresh of the page, the old information is pulled from the database.
Ive discovered that if I removed all of the form fields but one, it successfully updates AND sends to the database.
Title OR Description OR Price OR Category.
Checking the network tab within the browser whilst updating shows that for more than one input field, the put request fails and no information/payload is sent to the body within the request tab.
As a result, the database returns a NOT NULL error.
Based off Oliviers answer below, that setInput is only recognises one parameter, I can only imagine that this is what is breaking when there is more than one form field/input added. I unfortunatly dont know enough react to know if this is the case or not.
I see a problem in your state initialization => const [inputs, setInputs] = useState(menu.item_title, menu.item_price, menu.item_description, menu.item_category); is not correct, useState take a single parameter, here you must build an object representing the inputs.
Here is a solution using a function to initialize the inputs state, to prevent computing the object each time the component is re-rendered
function buildInputs(menu) {
return {
title: menu.item_title,
category: menu.item_category,
price: menu.item_price,
description: menu.item_description
};
}
const EditMenu = ({ menu }) => {
//editText function
const [inputs, setInputs] = useState(() => buildInputs(menu));
const { title, category, price, description } = inputs;
// Needed if you want the inputs to be updtated when the menu property is updated
useEffect(() => setInputs(buildInputs(menu)), [menu]);
const onChange = e => setInputs({ ...inputs, [e.target.name]: e.target.value });
...
You must also change the input value to reflect the state variable :
<input type="text" name="title" placeholder="Title"
className="form-control my-3" value={title} onChange={onChange} />
You should set your state like this:
const [inputs, setInputs] = useState({
title: menu.item_title,
price: menu.item_price,
category: menu.item_category,
description: menu.item_description
});
also you need to change value attributes to be variables rather than setting them to the menu values, for example:
//code
<input name="title" value={inputs.title} onChange={onChange}/>
cause values inside inputs are changeable by your onChange method, on the other hand, values inside menu object will remain with the same values.
I eventually figured out the issue.
By splitting my setInput useState into seperate individual useStates, I was able to get it to work.
So my origional code of...
const EditMenu = ({ menu }) => {
const [inputs, setInputs] = useState(menu.item_title, menu.item_price, menu.item_description, menu.item_category);
const { title, category, price, description } = inputs;
changed to this.
const EditMenu = ({ menu }) => {
const [item_title, setTitle] = useState(menu.item_title);
const [item_price, setPrice] = useState(menu.item_price);
const [item_description, setDescription] = useState(menu.item_description);
and the onChange function and form input...
const onChange = e =>
setInputs({ ...inputs, [e.target.name]: e.target.value });
<input... onChange={e => onChange(e)} />
changed to this...
value={item_title} onChange={e => setTitle(e.target.value)} />
value={item_price} onChange={e => setPrice(e.target.value)} />
value={item_description} onChange={e => setDescription(e.target.value)} />
In the end, Oliviers reasoing was correct even if the soloution didnt work for me. That my setInput only allowed for one parameter. Splitting it up allowed me to pass the remaining parameters.
Thank you everyone for the help, hopefully this might help someone else some day too!

Formsubmit.co form not working in reactapp

I added formsubmit service to my email form on my react application simple personal website. but it does not seem to be working. It does nothing. Does the extra javascript in there mess with the formsubmit service? I actually put my real email in just changed it for this post.
import React, { useState } from 'react';
import './styles.contactform.css';
function ContactForm() {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [message, setMessage] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
console.log(name, email, message)
setName('')
setEmail('')
setMessage('')
}
return (
<div className="contact-container">
<form className="contact-form" action="https://formsubmit.co/myemail#email.com" method="POST" onSubmit={handleSubmit}>
<input type="hidden" name="_next" value="https://notmicahclark.herokuapp.com/"/>
<input type="text" value={name} id="name" name="name" placeholder="Name..." onChange={(e) => setName(e.target.value)} required/>
<input type="email" value={email} id="email" name="email" placeholder="Email..." onChange={(e) => setEmail(e.target.value)} required/>
<img className="letter-img" src="contact_form_imagepng.png" alt="Mail Letter"/>
<input id="message" value={message} name="message" placeholder="Your message..." onChange={(e) => setMessage(e.target.value)}/>
<button type="submit" value="Submit">Submit</button>
</form>
</div>
);
}
export default ContactForm;
To overcome this issue, you can use the AJAX form feature provided by FormSubmit.
According to their documentation:
You can easily submit the form using AJAX without ever having your
users leave the page. — this even works cross-origin.
Please refer to their documentation about AJAX forms (sample code snippets are available): https://formsubmit.co/ajax-documentation
I've tested your code. The problem is that you are both using the form's HTML action field, and at the same time using your own method for form submission. Remove the action=... call and instead write this in your handleSubmit method.
fetch('https://formsubmit.co/ajax/myemail#email.com', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify(Object.fromEntries(new FormData(event.target))),
})
Should work like a charm. Add then and catch statements to your liking.

React Netlify form does not submit

Im making a personal website for training and I wanted to use Netlify form submission for /contact URL I tried adding just netlify , netlify='true', and other things like that but i just gives me 404 error everytime im trying to use Netlify form submission, but it doesnt seem to work no matter what I do, I followed several tutorials and repos but still does not work. It just gives 404 error and other stuff;
and please check my github repo,
My GitHub Repo's Link
and here is my Contact.js component;
import React, { Fragment, useState } from 'react';
import '../../App.css';
const encode = (data) => {
return Object.keys(data)
.map((key) => encodeURIComponent(key) + '=' + encodeURIComponent(data[key]))
.join('&');
};
const Contact = () => {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [text, setText] = useState('');
const handleSubmit = (e) => {
fetch('/', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: encode({
'form-name': 'contact',
name: name,
email: email,
text: text,
}),
})
.then((res) => {
console.log(res);
})
.catch((error) => alert(error));
e.preventDefault();
};
return (
<Fragment>
<div className='contact'>
<div className='contact-wrapper'>
<div className='title'>
<span>Contact me</span>
</div>
<div className='contact-form'>
<form
className='myform'
method='POST'
name='contact'
data-netlify='true'
onSubmit={(e) => handleSubmit(e)}
>
<input type='hidden' name='form-name' value='contact'></input>
<input
type='text'
placeholder='Your Name'
name='name'
value={name}
onChange={(e) => setName(e.target.value)}
></input>
<input
type='email'
placeholder='Your E-Mail'
name='email'
value={email}
onChange={(e) => setEmail(e.target.value)}
></input>
<textarea
placeholder='Your message'
name='message'
value={text}
onChange={(e) => setText(e.target.value)}
></textarea>
<button type='submit'>Send</button>
</form>
</div>
</div>
</div>
</Fragment>
);
};
export default Contact;
Netlify's forms work by their servers editing your html at deploy to add in their hooks for submitting the form.
With a React app, the form will not be visible in the html at deploy, so this won't work.
Netlify have a guide for how to set up their forms with SPAs, view it here: https://www.netlify.com/blog/2017/07/20/how-to-integrate-netlifys-form-handling-in-a-react-app/

Resources