The code bellow is fetching data from my API. In the same time, when I click on find button, I should get in console the response status 201, but I didn't get it, and the list of users is always identical on every post request. is it a problem in my fetch?
import React, {useEffect, useState} from 'react';
const Data = () => {
const [state, setState] = useState([]);
const [firstname, changeFirstname] = useState('');
const [lastname, changeLastname] = useState('');
useEffect(() => {
async function getData() {
const response = await fetch('http://localhost:8010/proxy');
const myJson = await response.json();
console.log(myJson);
setState(myJson)
}
getData();
}, []);
function changeFirstName(e) {
changeFirstname(e.target.value)
}
function changeLastName(e) {
changeLastname(e.target.value)
}
function saveVal() {
console.log(firstname + " " + lastname);
fetch('http://localhost:8010/proxy', {
method: "POST",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}, body: JSON.stringify({
firstName: firstname, lastName: lastname
})
}).then(response => response).then(data => console.log(data))
}
return (
<div>
<div className="fetch">
<ul>
{state.map(i => <li>{i.firstName + i.lastName}</li>)}
</ul>
<input onChange={changeFirstName} type="text" placeholder='add your name'/>
<input onChange={changeLastName} type="text" placeholder='add your last-name'/>
<button onClick={saveVal}>find</button>
</div>
</div>
);
}
export default Data;
Related
I'm building a simple React app that would create contacts and use them to schedule meetings.
I'm tried to build a backend that would save contacts submitted by client to a database. I used Express for the server and routing and postgresql for the database.
However after I implemented a post request method for adding contacts, the backend receives a null empty object after submitting a new contact. I included the frontend code component that implements the post request and the backend router.
Frontend
export const ContactsPage = (props) => {
const [name, setName] = useState('');
const [phone, setPhone] = useState('');
const [email, setEmail] = useState('');
const [duplicate, setDuplicate] = useState(false);
const handleSubmit = (e) => {
e.preventDefault();
/*
Add contact info and clear data
if the contact name is not a duplicate
*/
if(!duplicate){
props.addContacts(name,phone,email);
setName('');
setPhone('');
setEmail('');
}
//Post request
const data = { name, phone, email };
fetch('http://localhost:5000/api/contacts', {
method: 'POST',
mode: 'cors',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
data: JSON.stringify(data)
}).then(() => {
console.log({name,phone,email})
}).catch(error => {
// handle network errors
console.error(error);
});
};
/*
Using hooks, check for contact name in the
contacts array variable in props
*/
useEffect(() => {
const nameIsDuplicate = () => {
const found = props.contacts.find((contact) => contact.name === name);
if (found !== undefined) {
return true;
} else {
return false;
}
};
if (nameIsDuplicate()===true) {
setDuplicate(true);
} else {
setDuplicate(false);
}
}, [name,duplicate,props.contacts]);
return (
<div>
<section>
<h2>
Add Contact
{duplicate? "- Name already exists -" : ""}
</h2>
<ContactForm
name = {name}
email = {email}
phone = {phone}
setName = {setName}
setEmail = {setEmail}
setPhone = {setPhone}
onSubmit = {handleSubmit} />
</section>
<hr />
<section>
<h2>Contacts</h2>
<TileList
list={props.contacts}
/>
</section>
</div>
);
};
Backend:
app.use(bodyParser.json());
app.use(cors({ origin: 'http://localhost:3000'}));
app.get('/api/contacts', (request,response,next) => {
pool.query('SELECT * FROM contacts', (err, res) => {
if (err) return next(err);
response.json(res.rows);
});
});
app.post('/api/contacts', (request, response, next) => {
const { name, email, phone } = request.body;
pool.query(
'INSERT INTO contacts(name, phone, email) VALUES($1, $2, $3)',
[name,phone,email],
(err, res) => {
if (err) return next(err);
response.redirect('/api/contacts');
}
);
});
app.use((err,req,res,next) => {
res.json(err);
})
const port = 5000;
app.listen(port, () => console.log(`Server started on port ${port}`));
I figured out the problem. The post request header had the wrong key for request body. "data" instead of "body"
fetch('http://localhost:5000/api/contacts', {
method: 'POST',
mode: 'cors',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
I am making a meme sharing app. In that app there are total 2 apis of getting memes.
One for memes by all the users another is only for individual user.
In second api I am able to get the data as the user id is from 3rd api.
from here i get the id of each individual.
function UserProfile({memeid}) {
const token = localStorage.getItem("token");
const [response, setResponse] = useState({});
const [id, setId] = useState('')
const userData = async() => {
await axios
.get("http://localhost:8081/userInfo/me", {
headers: { Authorization: `Bearer ${token}` },
Accept: "application/json",
"Content-Type": "application/json",
})
.then((res) => {
setResponse(res.data)
setId(res.data.id)
memeid = id
})
.catch((err)=>{
console.log(err)
})
}
console.log(id)
useEffect(()=>{
userData()
},[])
Now I want this to be used in in another api. for that is have written this code.
function MemeById({id}) {
const [response, setResponse] = useState([])
const token = localStorage.getItem("token");
// const id = "632a119672ba0e4324b18c7d"
const memes = async () => {
await axios
.get("http://localhost:8081/memes/" + id, {
headers: { Authorization: `Bearer ${token}` },
Accept: "application/json",
"Content-Type": "application/json",
})
.then((res) => {
const data = res.data;
setResponse(res.data)
console.log(data);
})
.catch((err) => {
alert(err);
console.log(err);
});
};
useEffect(()=>{
memes()
},[])
I am calling these two at User
function User() {
let id;
return (
<div>
<UserProfile memeid={id}/>
<MemeById id = {id} />
</div>
)
}
I am getting the error for this.
How to solve this error
You're making a big mistake. I think you should learn more about state and props in react.
Problem :
In your User component, you're creating a variable and passing that variable into two other component. You're trying to update the value of props from UserProfile and expecting that updated value in MemeById which is not going to work.
Solution :
function User() {
const [memeId, setMemeId] = useState(null);
return (
<div>
<UserProfile updateId={(newId) => setMemeId(newId)}/>
<MemeById memeId = {memeId} />
</div>
)
}
And in your UserProfile component
function UserProfile({updateId}) {
...
const userData = async() => {
...
// memeid = id
updateId(res.data.id)
...
}
In you MemeById component:
function MemeById({memeId}) {
...
// use memeId here
...
}
Im writing an application using react and django rest. I am trying to update a post and then redirect back to the home screen, but sometimes the redirect happens before the put request.
As there is a Get request on the home page, that then gets called first and i do not see the updated values unless i refresh the page? Any suggestions?
Here is the page with the put request (updateNote())
import React, { useState, useEffect } from "react";
import { Link } from "react-router-dom";
import { ReactComponent as ArrowLeft } from "../assets/arrow-left.svg";
const NotePage = ({ match, history }) => {
let noteId = match.params.id;
let [note, setNote] = useState(null);
useEffect(() => {
getNote();
}, [noteId]);
let getNote = async () => {
let response = await fetch(`/api/get-note/${noteId}/`);
let data = await response.json();
setNote(data);
};
let updateNote = async () => {
fetch(`/api/get-note/${noteId}/update/`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(note),
});
};
let deleteNote = async () => {
fetch(`/api/get-note/${noteId}/delete/`, {
method: "DELETE",
headers: {
"Content-Type": "application/json",
},
});
history.push("/");
};
let handleSubmit = () => {
updateNote().then(history.push("/"));
};
let handleChange = (value) => {
setNote((note) => ({ ...note, body: value }));
console.log("Handle Change:", note);
};
return (
<div className="note">
<div className="note-header">
<h3>
<ArrowLeft onClick={handleSubmit} />
</h3>
<button onClick={deleteNote}>Delete</button>
</div>
<textarea
onChange={(e) => {
handleChange(e.target.value);
}}
value={note?.body}
></textarea>
</div>
);
};
export default NotePage;
Then here is the page it redirects to
import React, { useState, useEffect } from "react";
import ListItem from "../components/ListItem";
const NotesListPage = () => {
let [notes, setNotes] = useState([]);
useEffect(() => {
getNotes();
}, []);
let getNotes = async () => {
let response = await fetch("/api/get-notes/");
let data = await response.json();
setNotes(data);
};
return (
<div className="notes">
<div className="notes-header">
<h2 className="notes-title">☶ Notes</h2>
<p className="notes-count">{notes.length}</p>
</div>
<div className="notes-list">
{notes.map((note, index) => (
<ListItem key={index} note={note} />
))}
</div>
</div>
);
};
export default NotesListPage;
I want to make sure that history.push("/") doesnt get executed unitll the fetch request has returned a response
I suggest using the promise method and using '.then' or await just like that :
let updateNote = async () => {
let temp =await fetch(`/api/get-note/${noteId}/update/`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(note),
});
if(temp)
history.push("/")
};
If you want to navigate after the fetch request has resolved then the code needs to wait for them to settle. Don't forget to catch and/or handle any errors and rejected Promises appropriately.
Example:
const updateNote = async () => {
// return Promise to chain from
return fetch(`/api/get-note/${noteId}/update/`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(note),
});
};
const deleteNote = async () => {
try {
// wait for Promise to resolve
await fetch(`/api/get-note/${noteId}/delete/`, {
method: "DELETE",
headers: {
"Content-Type": "application/json",
},
});
history.push("/");
} catch(error) {
// log error, etc...
}
};
const handleSubmit = () => {
// pass a callback in .then
updateNote()
.then(() => history.push("/"))
.catch(error => {
// log error, etc...
});
};
I have data coming from my child component that needs to be passed on to the parent component. But my problem is I need to press the submit button twice. I tried to use the arrow function because I know this will update the state right away but not working. I tried to console.log the state inside useEffect and I see the changes. But when submit the state the the data is not appearing.
Child Component
const UploadFile = ({
uploadeditemListFile,
callChildFunction,
}) => {
const [list, setList] = useState(isList);
const [isOpen, setIsOpen] = useState(false);
const [itemListFile, setItemListFile] = useState([]);
const handleOnFileUpload = (e) => {
const formData = new FormData();
for (let i = 0; i < itemListFile.length; i++) {
formData.append('uploadCollection', itemListFile[i]);
}
axios({
method: 'POST',
url: `http://localhost:5000/api/seller/upload/${restaurantName}/${folderName}`,
data: formData,
headers: {
'Content-type': 'application/json',
},
}).then((res) => {
uploadeditemListFile(res.data);
});
};
useEffect(() => {
handleOnFileUpload();
}, [callChildFunction]);
return (
<>
HTML
</>
);
};
Parent Component
const RegisterSellerPage = ({ history }) => {
const [accountInfo, setAccountInfo] = useState({
restaurantName: '',
businessType: '',
costForOne: '',
fullname: '',
password: '',
confirmPassword: '',
email: '',
mobileno: '',
address: JSON.parse(localStorage.getItem('userCurrentLocation')) || '',
uploads: [],
});
const [isOpen, setIsOpen] = useState(false);
const [callChildFunction, setCallChildFunction] = useState(false);
const dispatch = useDispatch();
const handleOnSubmit = async (e) => {
e.preventDefault();
setCallChildFunction(true);
dispatch(registerSellerAccount(accountInfo));
};
useEffect(() => {
console.log(accountInfo.uploads)
}, [accountInfo.imgUrl, history]);
return (
<FormContainer>
<form noValidate onSubmit={handleOnSubmit} className='w-10/12 mx-auto'>
<div className='form-group w-full relative'>
<UploadFile
restaurantName={accountInfo.restaurantName}
folderName='menu'
name='uploadCollection'
accept='image/*'
multiple={true}
caption='Select a file'
isList={true}
uploadeditemListFile={(uploadeditemListFile) =>
setAccountInfo({ ...accountInfo, uploads: uploadeditemListFile }) <-- props
}
callChildFunction={callChildFunction}
/>
</div>
</form>
</FormContainer>
);
};
You are mixing async await and promises which might be causing your issue. Its not obvious but await always operates on the final value returned by the statements its awaiting. This means you are actually using await on the result of .then instead of the axios invocation. This may matter if an exception is thrown by the axios call.
const res = await axios({
method: 'POST',
url: `http://localhost:5000/api/seller/upload/${restaurantName}/${folderName}`,
data: formData,
headers: {
'Content-type': 'application/json',
},
});
uploadeditemListFile(res.data);
I am creating project in React /Django Rest Framework and I want to send Post request. My problem is that I am always sending string and I should send list of int.
My component look like this
const NewLecture = (props) => {
const[ lecture, setLecture] = useState({
title:'',
programs: [],
})
const dispatch = useDispatch()
const history = useHistory()
// console.log('this is history:', history)
const program_id = props.match.params.id;
//event handlers
const newLectureHandler = (event) => {
const{name, value}= event.target
setLecture({
...lecture,
[name]:value
})
};
useEffect(() => {
console.log('mounting in NewLecture');
dispatch(LecturesActions())
dispatch(GetPrograms())
}, [])
const handleSubmit = e =>{
e.preventDefault()
props.close()
dispatch(sendLecture(lecture, program_id, history))
}
const stringtoArray = (arg)=> {
console.log('this is arg', [arg]);
return [arg]
}
return (
<NewGradeStyled>
<div className="new-grade-style">
<h1>Create New Lecture</h1>
<form >
<div className="form-grade">
<label htmlFor="title">Lecture Name</label>
<input type="text" name="title" onChange={newLectureHandler}/>
</div>
<div className="form-grade">
<label htmlFor="programs">Program</label>
{/* <input type="number" name="programs" onChange={newLectureHandler}/> */}
<select name="programs" onChange={newLectureHandler}>
<option > </option>
{props.data ? <option value={props.data.id}>{props.data.name}</option> : ''}
</select>
</div>
<div className="btn-group">
<button className="save" onClick={handleSubmit}>Save</button>
<button onClick={props.close}>Cancle</button>
</div>
</form>
</div>
</NewGradeStyled>
)
}
export default withRouter(NewLecture)
and this is my action
export const sendLecture = (lecture) => (dispatch, getState) => {
const{title, programs} = lecture
const token = getState().token
const config = {
body: JSON.stringify(lecture),
method: "POST",
headers: new Headers({
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`
}),
body: JSON.stringify({title, programs})
};
fetch(`${baseUrl}/backend/api/lectures/new/`, config)
.then((res) => res.json())
.then((data)=>{
console.log('Post lecture action', data)
dispatch({type: 'GET_LECTURE_DATA', payload: data})
});
}
I expect to get this from JSON
{
"title":"some string"
"programs":[1]
}
reducer
const initialState = {
lecture_data:[],
}
export const authReducer = (state = initialState, action) => {
switch (action.type) {
case "GET_LECTURE_DATA": {
const lecture_data = action.payload;
return { ...state, lecture_data };
}
default:
return state;
}
}
If I send it as input type= "number" result is always the same I get error "Expected a list of items but got type "str"."
I don´t kow how I should change it. Do you have any Ideas?
In this part:
const config = {
body: JSON.stringify(lecture),
method: "POST",
headers: new Headers({
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`
}),
body: JSON.stringify({ title, programs })
};
you set the body property twice. Is that intentional?
You write the api expects a list. Did you mean to pass this body: JSON.stringify( [title, programs ]) Although that would send an array of objects of which the first item is title, and the second is programs. Can you clarify what the API expects? And what the structure of title and programs looks like?