I'm learning React and atm i'm making a crud App for Employee Data. Now the problem I'm having is that when i click on Add New button or Update button my component loads for respective features but my old component which is my Table of Data for all my employees stays open along with the new component. I want my Table of data to be disabled or hidden until my New Employee is added or old employee is updated on submission but i'm unable to do that... I made the AddNew.js for adding new employees, UpdateMember.js for updating old employees and then imported these components in my Table.js file which is then returned in the App.js component
The update component loads right on the spot of the update button itself which is another problem for me right now.
almost same is happening with Update even worse with this one
AddNew.js
function AddNew() {
const [list, setList] = useState(null);
const [Name, setName] = useState("");
const [Department, setDepartment] = useState("");
const [Salary, setSalary] = useState("");
const Data = {
name: Name,
department: Department,
salary: Salary,
};
const PostData = () => (event) => {
let header = new Headers();
header.append("Content-Type", "application/json");
// header.append("Accept", "application/json");
//
return (
fetch(PostUrl, {
method: "POST",
headers: header,
body: JSON.stringify(Data),
})
///
.then(() => {
fetch(BaseUrl, { method: "GET", headers: header })
//
.then((response) => response.json())
.then((result) => {
console.log(result);
setList(result);
});
})
);
};
return (
<div>
<form onSubmit={PostData}>
<h2>Add New Members</h2>
<span>* All fields are required</span>
<div className="outerDiv">
<div className="innerDiv">
<input
type="text"
autoComplete="off"
name="name"
placeholder="Name"
onChange={(event) => setName(event.target.value)}
/>
</div>
<div className="innerDiv">
<input
type="text"
autoComplete="off"
name="Department"
placeholder="Department"
onChange={(event) => setDepartment(event.target.value)}
/>
</div>
<div className="innerDiv">
<input
type="text"
autoComplete="off"
name="Salary"
placeholder="Salary"
onChange={(event) => setSalary(event.target.value)}
/>
</div>
<input className="btn btn-primary" type="submit" value="Save" />
</div>
</form>
</div>
);
}
export default AddNew;
UpdateMember.js
const UpdateRow = () => (event) => {
const PutData = {
name: Name,
department: Department,
salary: Salary,
};
console.log("Update Clicked");
let header = new Headers();
header.append("Content-Type", "application/json");
header.append("Accept", "application/json");
fetch(PutUrl, {
method: "PUT",
headers: header,
body: JSON.stringify(PutData),
})
.then((response) => response.json())
.then((response) => console.log(response))
.then(() => {
fetch(BaseUrl, { method: "GET", headers: header })
.then((res) => res.json())
.then((result) => {
setList(result);
});
});
};
return (
<div>
<form onSubmit={UpdateRow}>
<span className="text">* All fields are required</span>
<hr />
<div>
<h2>Update Information</h2>
<div className="outerDiv">
<div className="innerDiv">
<input
type="text"
autoComplete="off"
name="name"
placeholder="Name"
onChange={(event) => setName(event.target.value)}
/>
</div>
<div className="innerDiv">
<input
type="text"
autoComplete="off"
name="Department"
placeholder="Department"
onChange={(event) => setDepartment(event.target.value)}
/>
</div>
<div className="innerDiv">
<input
type="text"
autoComplete="off"
name="Salary"
placeholder="Salary"
onChange={(event) => setSalary(event.target.value)}
/>
</div>
<button
style={{ float: "right" }}
className="button btn-warning"
type="submit"
>
Update
</button>
</div>
</div>
</form>
</div>
);
}
export default UpdateMember;
Table.js
function Table() {
//
const [list, setList] = useState([]);
useEffect(() => {
let mounted = true;
getList().then((items) => {
if (mounted) {
setList(items);
}
});
return () => (mounted = false);
}, []);
//
const DeleteRow = (id) => (event) => {
let header = new Headers();
header.append("Content-Type", "application/json");
header.append("Accept", "application/json");
return fetch(DeleteUrl + id, { method: "DELETE", headers: header }).then(
() => {
fetch(BaseUrl, { method: "GET", headers: header })
.then((response) => response.json())
.then((result) => {
console.log(result);
setList(result);
});
}
);
};
//
return (
<div>
<h1>Employees Data</h1>
<Router>
<Link to="/Addnew" target="_blank">
<button
style={{ float: "right" }}
className="button btn-primary LinkButton"
>
Add New
</button>
</Link>
<Route path="/AddNew">
<AddNew />
</Route>
</Router>
<table>
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Department</th>
<th>Salary</th>
<th>Actions</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{list.map((item) => (
<tr key={item.id}>
<td>
<center>{item.id}</center>
</td>
<td>
<center>{item.name}</center>
</td>
<td>
<center>{item.department}</center>
</td>
<td>
<center>{item.salary}</center>
</td>
<td>
<center>
<button
// key={item.id}
className="button btn-danger"
onClick={DeleteRow(item.id)}
>
Delete
</button>
</center>
</td>
<td>
<center>
<Router>
<Link to="/UpdateMember">
<button className="button btn-warning LinkButton">
Update
</button>
</Link>
<Switch>
<Route path="/UpdateMember">
<UpdateMember id={item.id} />
</Route>
</Switch>
</Router>
</center>
</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
export default Table;
App.js
function App() {
return (
<Table />
);
}
export default App;
I think that some conditional rendering could help you out with the problem.
Check it out here.
You can create a new variable called isLoading which will be set to true when you start a fetch and false after the fetch has finished. Then after that you can use it to check if isLoading is true, if it is true, do not show the table (conditional rendering)
And another suggestion would be creating a spinner to show when loading is true and hide when it is false, so that the user will know that it is loading.
Related
I have POST function and it's post data to sharepoint list after that I need to refresh the page to show the data. I tried to run GET function put it Didn't Print the data
after clicking on arrow 1 POST function start and send the data to sharepoint list
after the data should be visible here with the 3 but it didn't show I need to refresh the page to show the data
-I got an idea that to print temporary UseState to show the data but I dont know how to do it
here is my latest code
function Feed(props) {
const [data,setdata] = useState(props)
return (
<div>
{data.data.map((item) => {
var spFormated = Moment(item.fields.Date).format('MM/DD/YYYY')
if (formated == spFormated ) {
if(item.fields.Hours<=2){
return(
<React.Fragment key={item.id}>
<div className="taskcolorback-div" />
<button className="taskcolor-button" />
<input className="tasktext-b" defaultValue={Moment(item.fields.Date).format('MM/DD/YYYY')}></input>
<button className="taskwhite-button" />
<b className="timeinline">{item.fields.Hours}Hr</b>
<img className="vector-icon" alt="" src="icons8-chevron-right-64.png" />
</React.Fragment>)
}
else if(item.fields.Hours==3){
return(
<React.Fragment key={item.id}>
<div className="taskcolorback-div3" />
<button className="taskcolor-button3" />
<input className="tasktext-b3" defaultValue={Moment(item.fields.Date).format('MM/DD/YYYY')}></input>
<button className="taskwhite-button3" />
<b className="timeinline3">{item.fields.Hours}Hr</b>
<img className="vector-icon3" alt="" src="icons8-chevron-right-64.png" />
</React.Fragment>)
}
else if(item.fields.Hours==4){
return(
<React.Fragment key={item.id}>
<div className="taskcolorback-div4" />
<button className="taskcolor-button4" />
<input className="tasktext-b4" defaultValue={Moment(item.fields.Date).format('MM/DD/YYYY')}></input>
<button className="taskwhite-button4" />
<b className="timeinline4">{item.fields.Hours}Hr</b>
<img className="vector-icon4" alt="" src="icons8-chevron-right-64.png" />
</React.Fragment>)
}
else if(item.fields.Hours>=5){
return(
<React.Fragment key={item.id}>
<div className="taskcolorback-div5" />
<button className="taskcolor-button5" />
<input className="tasktext-b5" defaultValue={Moment(item.fields.Date).format('MM/DD/YYYY')}></input>
<button className="taskwhite-button5" />
<b className="timeinline5">{item.fields.Hours}Hr</b>
<img className="vector-icon5" alt="" src="icons8-chevron-right-64.png" />
</React.Fragment>)
}
return(
<>
<React.Fragment key={item.id}>
<div className="taskcolorback-div" />
<button className="taskcolor-button" />
<input className="tasktext-b" defaultValue={Moment(item.fields.Date).format('MM/DD/YYYY')}></input>
<button className="taskwhite-button" />
<b className="timeinline">{item.fields.Hours}Hr</b>
<img className="vector-icon" alt="" src="icons8-chevron-right-64.png" />
</React.Fragment>
</>
)
}
// 👇️ render nothing
return console.log("null");
})}
</div>
);
}
Note: The map function will get the data from API
import { graphConfig,graphConfigh } from "./authConfig";
/**
* Attaches a given access token to a MS Graph API call. Returns information about the user
* #param accessToken
*/
export async function callMsGraph(accessToken) {
const headers = new Headers();
const bearer = `Bearer ${accessToken}`;
headers.append("Authorization", bearer);
const options = {
method: "GET",
headers: headers
};
return fetch(graphConfig.graphMeEndpoint, options)
.then(response => response.json())
.catch(error => console.log(error));
}
//-------------------------------
export async function PostData(accessToken) {
const headers = new Headers();
const bearer = `Bearer ${accessToken}`;
headers.append("Authorization", bearer);
const options = {
method: "post",
headers: {
'Authorization': bearer,
'Content-Type': 'application/json'
},
body: JSON.stringify({fields: {Title: 'TEST',Date: '08/13/2022',Hours:"3"}})
};
return fetch(graphConfigh.graphMeEndpointh, options)
.catch(error => console.log(error));
}
I did looking for but i did not find an answer for my problem.
I need to create a dynamic form with dynamic fields, with the order that the user need.
import { useState } from "react";
const DemoLateral = () => {
const itemDataObject = {
title_item_lateral: '' ,
text_item_lateral: [],
image_lateral: [
{
title_image_lateral: '',
path_image_lateral: '',
}
],
document_lateral: [],
links: [
{
title_link:'' ,
link: ''
}
]
};
const addFields = () => {
let newItemField;
newItemField = itemDataObject;
setItems([...items, newItemField]);
};
const [items, setItems] = useState([]);
const [select, setSelect] = useState([]);
console.log(items);
console.log('select: ', select);
const handleChange = () => {
//let index =
//let name = items[i][e.target.name]=[e.target.value];
console.log();
};
const submitForm = (e) => {
e.preventDefault();
};
console.log(select);
return (
<>
<h3 className="ms-5 mb-5"> AÑADIR ITEMS </h3>
<div className="container">
<form onSubmit={submitForm} className=''>
<div>
{items.map((input, i)=> (
<>
<div className="row align-items-center row mb-4" key={i}>
<label htmlFor="exampleFormControlSelect1">Selecciona el Campo</label>
<div className="col-2" key={i}>
<select className="form-control" id="exampleFormControlSelect1"
onChange={(e) => setSelect([select[i]=e.target.value])} key={i}>
<option>Subtitulo</option>
<option>Imagen</option>
<option>Link</option>
<option>Texto</option>
</select>
</div>
<div className='col-8'>
<input
placeholder="desde From"
id={i}
className='form-control'
value={select[i]}
onChange= {handleChange(i)}
type="text"
required
/>
</div>
<button className="btn btn-danger col-1" >Borrar</button>
</div>
</>
))
}
</div>
<button className="btn btn-success me-4 mt-5" type='submit'>AddSubmit</button>
</form>
<div className="mt-5 text-center">
<button className="btn btn-primary me-4 mb-4" value='items' onClick={addFields}>Add Items</button>
</div>
</div>
</>
);
};
export default DemoLateral;
with this code i try to create a dynamic form with fields, that would be set in the form like the user need:
p.e:
'subtitle'
'image'
'text'
'text'
'link'
'image'
for this i create a select to choose the type of field, and try to put the select in the attribute name, for then when submit all works.
But i can not achieve. :-(
Where is my wrong....
maybe there are other way to do the same kind of form?
I'm passing data from am AddItem modal in react to a table in the NewInvoice component. The data is being populated to the table successfully but modal does not close after clicking the save button. Kindly assist on what i could be missing on this.
NewInvoice.js
const [itemOpen, setitemOpen] = useState(false);
<div className="new-invoice-client">
<FormDataTable itemOpen={itemOpen}/>
</div>
<div
className="new-item-links"
style={{ marginLeft: "35px", marginTop: "35px" }}
>
<Button onClick={() => setitemOpen(true)}>
<BsPlus />
Add an Item
{itemOpen && <AddItem setitemOpen={setitemOpen} />}
</Button>
</div>
The <FormInvoiceTable/> is passed to the NewInvoice parent component as shown below.
FormInvoieTable.js
function FormDataTable(props) {
const [tableData, setTableData] = useState([]);
// console.log(tableData)
const tableRows = tableData.map((value, index) => {
return (
<tr key={index}>
<td>{value.item}</td>
<td>{value.amount}</td>
<td>{value.rate}</td>
<td>{value.quantity}</td>
<td>{value.description}</td>
</tr>
);
});
const addRows = (data) => {
const totalData = tableData.length;
data.id = totalData + 1;
const updatedtableData = [...tableData];
updatedtableData.push(data);
setTableData(updatedtableData);
};
return (
<React.Fragment>
<table className="table">
<thead>
<tr>
<th>Item</th>
<th>Description</th>
<th>Qty</th>
<th>Rate</th>
<th>Amount</th>
</tr>
</thead>
<tbody>{tableRows}</tbody>
</table>
<AddItem func={addRows}/>}
</React.Fragment>
);
}
AddItem.js Modal
function AddItem(props) {
const [item, setItem] = useState("");
const [amount, setAmount] = useState("");
const [rate, setRate] = useState("");
const [quantity, setQuantity] = useState("");
const [description, setDescription] = useState("");
const clearState = () => {
setItem("");
setAmount("");
setRate("");
setQuantity("");
setDescription("");
};
const handleSubmit = (event) => {
event.preventDefault();
const formInputData = {
item,
amount,
rate,
quantity,
description,
};
props.func(formInputData);
// clearState();
props.setitemOpen(false)
};
return (
<div className="modalBackground">
<div className="modalContainer">
<div className="title">
<h1>New Item</h1>
</div>
<div className="modal-form-container">
<form className="register-form">
<input
className="register-input"
name="item"
onChange={(e) => setItem(e.target.value)}
value={item}
placeholder="Item"
/>
<input
className="register-input"
name="amount"
value={amount}
placeholder="Amount"
onChange={(e) => setAmount(e.target.value)}
/>
<input
className="register-input"
placeholder="Rate"
name="rate"
value={rate}
onChange={(e) => setRate(e.target.value)}
/>
<input
className="register-input"
name="quantity"
placeholder="Quantity"
value={quantity}
onChange={(e) => setQuantity(e.target.value)}
/>
<input
className="register-input"
style={{ width: "600px", height: "80px" }}
type="text"
value={description}
placeholder="Description"
onChange={(e) => setDescription(e.target.value)}
/>
<div className="modal-buttons" style={{ justifyContent: "center" }}>
<button onClick={handleSubmit}>Save</button>
<button onClick={() => props.setitemOpen(false)}>cancel</button>
</div>
</form>
</div>
</div>
</div>
);
}
Your are creating component <AddItem/> two times.
When you create it in FormDataTable component you don't pass it prop setitemOpen. You are passing only addRows function as a prop :
<AddItem func={addRows}/>
One solution would be to pass setitemOpen={setitemOpen} prop to FormDataTable component and call it in addRow method with argument false. Also, remove AddItem component from NewInvoice component and create it only in FormDataTable component based on itemOpen
Here is code snippet:
NewInvoice.jsx
import React from "react";
import FormDataTable from "./FormInvoieTable";
import { useState } from "react";
import Button from "#mui/material/Button";
export default function NewInvoice(props) {
const [itemOpen, setitemOpen] = useState(false);
return (
<>
<div className="new-invoice-client">
<FormDataTable itemOpen={itemOpen} setitemOpen={setitemOpen} />
</div>
<div
className="new-item-links"
style={{ marginLeft: "35px", marginTop: "35px" }}
>
<Button onClick={() => setitemOpen(true)}>Add an Item</Button>
</div>
</>
);
}
Then in FormDataTable component, modify addRows method like this:
FormDataTable.jsx
import React from "react";
import AddItem from "./AddItem";
import { useState } from "react";
export default function FormDataTable(props) {
const [tableData, setTableData] = useState([]);
const { itemOpen } = props;
const tableRows = tableData.map((value, index) => {
return (
<tr key={index}>
<td>{value.item}</td>
<td>{value.amount}</td>
<td>{value.rate}</td>
<td>{value.quantity}</td>
<td>{value.description}</td>
</tr>
);
});
const addRows = (data) => {
const totalData = tableData.length;
data.id = totalData + 1;
const updatedtableData = [...tableData];
updatedtableData.push(data);
setTableData(updatedtableData);
props.setitemOpen(false);
};
return (
<React.Fragment>
<table className="table">
<thead>
<tr>
<th>Item</th>
<th>Description</th>
<th>Qty</th>
<th>Rate</th>
<th>Amount</th>
</tr>
</thead>
<tbody>{tableRows}</tbody>
</table>
{itemOpen && <AddItem func={addRows} />}
</React.Fragment>
);
}
AddItem.jsx
import React from "react";
import { useState } from "react";
export default function AddItem(props) {
const [item, setItem] = useState("");
const [amount, setAmount] = useState("");
const [rate, setRate] = useState("");
const [quantity, setQuantity] = useState("");
const [description, setDescription] = useState("");
console.log(props);
const clearState = () => {
setItem("");
setAmount("");
setRate("");
setQuantity("");
setDescription("");
};
const handleSubmit = (event) => {
event.preventDefault();
const formInputData = {
item,
amount,
rate,
quantity,
description,
};
props.func(formInputData);
// clearState();
};
return (
<div className="modalBackground">
<div className="modalContainer">
<div className="title">
<h1>New Item</h1>
</div>
<div className="modal-form-container">
<form className="register-form">
<input
className="register-input"
name="item"
onChange={(e) => setItem(e.target.value)}
value={item}
placeholder="Item"
/>
<input
className="register-input"
name="amount"
value={amount}
placeholder="Amount"
onChange={(e) => setAmount(e.target.value)}
/>
<input
className="register-input"
placeholder="Rate"
name="rate"
value={rate}
onChange={(e) => setRate(e.target.value)}
/>
<input
className="register-input"
name="quantity"
placeholder="Quantity"
value={quantity}
onChange={(e) => setQuantity(e.target.value)}
/>
<input
className="register-input"
style={{ width: "600px", height: "80px" }}
type="text"
value={description}
placeholder="Description"
onChange={(e) => setDescription(e.target.value)}
/>
<div className="modal-buttons" style={{ justifyContent: "center" }}>
<button onClick={handleSubmit}>Save</button>
<button onClick={() => props.setitemOpen(false)}>cancel</button>
</div>
</form>
</div>
</div>
</div>
);
}
My application doesn't redirect me to /quiz page after submit the form, browser always show Cannot POST /quiz.
My goal is: i need to redirect from /form page to /quiz page with all the data that has been submitted.
Should i add a route for /quiz?
Frontend:
form.jsx:
const submit = async (e) => {
/* e.preventDefault(); */
await FormService.store(storedata)
.then((res) => {
console.log(res);
})
.catch((err) => {
return err;
});
};
return (
<div className="container">
<div className="header">
<div className="title">
<h1>Apply for a Position :</h1>
</div>
</div>
<Divider style={{ maxWidth: '1000px', marginLeft: '250px' }} />
<div id="content">
<div id="formWrapper">
<form
id="msform"
method="post"
action="/quiz"
enctype="multipart/form-data"
>
<fieldset id="fieldset3">
<h2 class="fs-title">
Please complete the form below for a position with us.
</h2>
<h3 class="fs-subtitle">Reference 0001</h3>
{/* <div class="fs-error"></div> */}
<div class="wrapper">
<label for="CV">
Upload CV <span>*</span>:
</label>
<input
type="file"
name="myFile"
id="cv"
onChange={handleCVChange}
accept="application/msword, application/pdf, .docx"
placeholder="Cover Letter"
required
/>
<label for="coverLetter">Cover Letter :</label>
<textarea
type="text"
name="coverLetter"
value={storedata.coverLetter}
onChange={handleChange}
id="coverLetter"
placeholder="Your Cover Letter"
/>
</div>
<br />
<input
type="submit"
name="submit"
class="submit action-button"
value="Submit"
onClick={submit}
/>
</fieldset>
</form>
</div>
</div>
</div>
);
};
export default Form;
quiz.jsx:
import React, { useState, useContext } from 'react'
import { QuizContext } from '../Helpers/Contexts'
import { Questions } from '../Helpers/QuestionBank'
function Quizz() {
const { score, setscore, setGameState } = useContext(QuizContext)
const [currQuestion, setcurrQuestion] = useState(0) //state de numero de current question: 0/1/2
const [optionChosen, setoptionChosen] = useState("") //state de l'option choisi: A ou B ou C ou D
const nextQuestion = () => {
if (Questions[currQuestion].answer === optionChosen) {
setscore(score + 1);
}
//alert(score);
setcurrQuestion(currQuestion + 1);
}
const finishQuiz = () => {
if (Questions[currQuestion].answer === optionChosen) {
setscore(score + 1);
}
setGameState("endScreen")
}
return (
<div className='Quiz'>
<h1>{Questions[currQuestion].prompt}</h1>
<div className='options'>
<button onClick={() => setoptionChosen("A")}>{Questions[currQuestion].optionA}</button>
<button onClick={() => setoptionChosen("B")}>{Questions[currQuestion].optionB}</button>
<button onClick={() => setoptionChosen("C")}>{Questions[currQuestion].optionC}</button>
<button onClick={() => setoptionChosen("D")}>{Questions[currQuestion].optionD}</button>
</div>
{currQuestion === Questions.length - 1
?
(
<button onClick={finishQuiz}>Finish Quiz</button>
)
:
(
<button onClick={nextQuestion}>Next Question</button>
)}
</div>
)
}
export default Quizz
backend:
formRoute.js:
const express = require('express')
const router = express.Router()
const FormController = require('../controllers/FormController')
const upload = require('../Middleware/upload')
router.post('/store', upload.single('cv'), FormController.store)
module.exports = router
Formcontroller.js:
const form = require('../models/FormModel')
module.exports = {
store: (req, res, next) => {
let candidate = new form({
coverLetter: req.body.coverLetter,
cv: req.body.cv
})
if (req.file) {
candidate.cv = req.file.path
}
candidate.save()
.then(response => {
res.json({
success: true,
message: 'Candidate added successfully!',
data: candidate,
})
})
.catch(error => {
res.json({
success: false,
message: 'An error occured!',
error: error,
})
})
}
}
src/App.js:
import './App.css';
import { BrowserRouter, Routes, Route } from 'react-router-dom'
import Home from './views/Home/Home';
import Formulaire from './views/Form/Formulaire';
import Quiz from './views/Quiz/Quiz';
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/form" element={<Formulaire />} />
<Route path="/quiz" element={<Quiz />} />
</Routes>
</BrowserRouter>
);
}
export default App;
First install react-router-dom to your project
Then Replace your form.jsx from this
Form.jsx
import { useNavigate } from 'react-router-dom';
const navigate = useNavigate();
const submit = async (e) => {
/* e.preventDefault(); */
await FormService.store(storedata)
.then((res) => {
console.log(res);
})
.catch((err) => {
return err;
});
};
function gotoQuiz() {
navigate('/quiz')
}
return (
<div className="container">
<div className="header">
<div className="title">
<h1>Apply for a Position :</h1>
</div>
</div>
<Divider style={{ maxWidth: '1000px', marginLeft: '250px' }} />
<div id="content">
<div id="formWrapper">
<form
onSubmit={gotoQuiz}
id="msform"
method="post"
enctype="multipart/form-data"
>
<fieldset id="fieldset3">
<h2 class="fs-title">
Please complete the form below for a position with us.
</h2>
<h3 class="fs-subtitle">Reference 0001</h3>
{/* <div class="fs-error"></div> */}
<div class="wrapper">
<label for="CV">
Upload CV <span>*</span>:
</label>
<input
type="file"
name="myFile"
id="cv"
onChange={handleCVChange}
accept="application/msword, application/pdf, .docx"
placeholder="Cover Letter"
required
/>
<label for="coverLetter">Cover Letter :</label>
<textarea
type="text"
name="coverLetter"
value={storedata.coverLetter}
onChange={handleChange}
id="coverLetter"
placeholder="Your Cover Letter"
/>
</div>
<br />
<input
type="submit"
name="submit"
class="submit action-button"
value="Submit"
onClick={submit}
/>
</fieldset>
</form>
</div>
</div>
</div>
);
};
export default Form; ````
I am using React Hooks and am created a form to submit blog posts. I am having trouble writing the submitPost logic. I have a post, and setPost variable. setPost doesn't seem to be updating post with the new post in the submitPost function, so my api call function createPost isn't receiving the new req.body. But when I created a second function changePost(), post is updated.
This is my code.
export default function NewPost({ props }) {
const [post, setPost] = useState({
title: "",
img: "",
content: "",
user_id: 0,
});
const [img, setImg] = useState("");
const [title, setTitle] = useState("");
const [content, setContent] = useState("");
const [userId, setUserId] = useState(0);
useEffect(() => {
const handleUser = async () => {
try {
const response = await verifyUser();
console.log(response);
setUserId(response.user.id);
} catch (error) {
console.log(error);
}
};
handleUser();
});
const changePost = () => {
const newPost = {
title: title,
img: img,
content: content,
user_id: userId,
};
setPost(newPost);
console.log(post);
};
const submitPost = async (e) => {
e.preventDefault();
console.log(userId);
try {
console.log(title);
changePost();
console.log("submitPost", post);
await createPost(post);
props.history.push("/posts");
} catch (error) {
console.log(error);
}
};
console.log(post);
return (
<div>
<Nav />
<div class="ui main text container segment mt-100">
<div class="ui huge header salmon">New Blog </div>
<form class="ui form" onSubmit={submitPost}>
<div class="field">
<label> Title </label>
<input
type="text"
name="title"
value={title}
onChange={(e) => setTitle(e.target.value)}
placeholder="title"
/>
</div>
<div class="field">
<label> Image </label>
<input
type="text"
name="img"
value={img}
onChange={(e) => setImg(e.target.value)}
placeholder="image"
/>
</div>
<div class="field">
<label> Body </label>
<textarea
name="content"
value={content}
onChange={(e) => setContent(e.target.value)}
placeholder="blog post goes here"
>
{" "}
</textarea>
</div>
<input class="ui teal big basic button" type="submit" />
</form>
</div>
</div>
);
}
It won't work. You're trying to create a post where your post variable is not yet updated. You don't need to create so many variables, just use the post variable.
Try using the below code.
export default function NewPost({ props }) {
const [post, setPost] = useState({
title: "",
img: "",
content: "",
user_id: 0,
});
useEffect(() => {
const handleUser = async () => {
try {
const response = await verifyUser();
console.log(response);
setPost({...post, user_id: response.user.id});
} catch (error) {
console.log(error);
}
};
handleUser();
});
const submitPost = async (e) => {
e.preventDefault();
console.log(userId);
try {
console.log(title);
console.log("submitPost", post);
await createPost(post);
props.history.push("/posts");
} catch (error) {
console.log(error);
}
};
console.log(post);
return (
<div>
<Nav />
<div class="ui main text container segment mt-100">
<div class="ui huge header salmon">New Blog </div>
<form class="ui form" onSubmit={submitPost}>
<div class="field">
<label> Title </label>
<input
type="text"
name="title"
value={title}
onChange={(e) => setPost({...post, title: e.target.value})}
placeholder="title"
/>
</div>
<div class="field">
<label> Image </label>
<input
type="text"
name="img"
value={img}
onChange={(e) => setPost({...post, img: e.target.value})}
placeholder="image"
/>
</div>
<div class="field">
<label> Body </label>
<textarea
name="content"
value={content}
onChange={(e) => setPost({...post, content: e.target.value})}
placeholder="blog post goes here"
>
{" "}
</textarea>
</div>
<input class="ui teal big basic button" type="submit" />
</form>
</div>
</div>
);
}
just do this .
useEffect(()=>{
},[JSON.stringify(post)])..
setPost({ title,img,content,user_id});