React Follow Function activates on page load - reactjs

I am trying to implement a follow/unfollow function in a react rails-api web application. Currently the follow and unfollow post/delete just fine when I click the follow/unfollow button.
However, whenever a user visits another users page it will follow/unfollow when the page loads without clicking the follow/unfollow button. I do not understand why this is happening since I have, for my post/delete, the useEffect second param set to go off when the state for my follow/unfollow changes.
Please help me figure out why this is happening and how to prevent this. Let me know if more information is needed.
import React, {useState, useEffect} from 'react'
import {Link, useParams} from 'react-router-dom'
import decode from 'jwt-decode'
function NotUserPage() {
const {id} = useParams()
const [user, setUser] = useState({})
const loggedUser = decode(localStorage.getItem("token"))
const username = loggedUser.username
const userId = loggedUser.user_id
const [followUnFollow, setFollowUnFollow] = useState("true")
const toggleFollowUnFollow = () => {
setFollowUnFollow(!followUnFollow)
}
const fetchUserData = () => {
fetch(`http://localhost:3000/users/${id}`)
.then(res => res.json())
.then(data => setUser(data))
}
useEffect(() => {
fetchUserData()
}, [])
const unFollow = () => {
fetch(`http://localhost:3000/users/${id}/unfollow`, {
method: "POST",
body: JSON.stringify({
follower_id: userId,
followee_id: id
}),
headers: {
"Content-type": "application/json",
"Authorization": `bearer ${localStorage.getItem("token")}`,
},
})
.then(res => res.json())
.then(data => console.log(data))
}
useEffect(() => {
unFollow()
}, [followUnFollow])
const handleFollow = () => {
fetch(`http://localhost:3000/users/${id}/follow`, {
method: "POST",
body: JSON.stringify({
follower_id: userId,
followee_id: id
}),
headers: {
"Content-type": "application/json",
"Authorization": `bearer ${localStorage.getItem("token")}`,
},
})
.then(res => res.json())
.then(data => console.log(data))
}
useEffect(() => {
handleFollow()
}, [followUnFollow])
const fButton = () => {
toggleFollowUnFollow() ? handleFollow() : unFollow()
}
return (
<div>
{user.username}
<button onClick={fButton}>follow</button>
</div>
)
}
export default NotUserPage

import React, {useState, useEffect} from 'react'
import {Link, useParams} from 'react-router-dom'
import decode from 'jwt-decode'
function NotUserPage() {
const {id} = useParams()
const [user, setUser] = useState({})
const loggedUser = decode(localStorage.getItem("token"))
const username = loggedUser.username
const userId = loggedUser.user_id
const [following, setFollowing] = useState(false)
const fetchUserData = () => {
fetch(`http://localhost:3000/users/${id}`)
.then(res => res.json())
.then(data => setUser(data))
}
useEffect(() => {
fetchUserData()
}, [])
const unFollow = () => {
fetch(`http://localhost:3000/users/${id}/unfollow`, {
method: "POST",
body: JSON.stringify({
follower_id: userId,
followee_id: id
}),
headers: {
"Content-type": "application/json",
"Authorization": `bearer ${localStorage.getItem("token")}`,
},
})
.then(res => res.json())
.then(data => console.log(data))
.then(() => setFollowing(false))
}
const handleFollow = () => {
fetch(`http://localhost:3000/users/${id}/follow`, {
method: "POST",
body: JSON.stringify({
follower_id: userId,
followee_id: id
}),
headers: {
"Content-type": "application/json",
"Authorization": `bearer ${localStorage.getItem("token")}`,
},
})
.then(res => res.json())
.then(data => console.log(data))
.then(() => setFollowing(true))
}
const fButton = () => following ? unFollow() : handleFollow();
return (
<div>
{user.username}
<button onClick={fButton}>follow</button>
</div>
)
}
export default NotUserPage

Related

converting custom react function to async

I made this custom hook.
import axios from "axios";
import Cookies from "js-cookie";
import React from "react";
const useGetConferList= () => {
let token = JSON.parse(localStorage.getItem("AuthToken"));
const Idperson = JSON.parse(Cookies.get("user")).IdPerson;
const [response, setResponse] = React.useState();
const fetchConfer= (datePrensence, idInsurance, timePrensence) => {
axios({
method: "post",
url: `${process.env.REACT_APP_API_URL_API_GET_ERJASERVICE_LIST}`,
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
data: JSON.stringify({
datePrensence,
idInsurance,
Idperson,
searchfield: "",
timePrensence: parseInt(timePrensence) * 60,
}),
})
.then((r) => {
setResponse(r.data.Data);
})
.catch(() => alert("NetworkError"));
};
return { fetchConfer, response };
};
export default useGetConferList;
as you can see I export the fetchConfer function. but I want to make it async. for example, calling the function and then doing something else like this:
fetchConfer(Date, Time, Id).then((r) => {
if (search !== "") {
window.sessionStorage.setItem(
"searchList",
JSON.stringify(
r.data
)
);
}
});
as you can see in non async situation, I can't use then.
You can try this
const fetchConfer = async (datePrensence, idInsurance, timePrensence) => {
try {
const response = await axios({
method: "post",
url: `${process.env.REACT_APP_API_URL_API_GET_ERJASERVICE_LIST}`,
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
data: JSON.stringify({
datePrensence,
idInsurance,
Idperson,
searchfield: "",
timePrensence: parseInt(timePrensence) * 60,
}),
})
setResponse(response.data.Data);
// need to return data
return response.data.Data
} catch(error) {
alert("NetworkError")
}
};
use the function in another async function
const someAsyncFunc = async () => {
// try catch
const r = fetchConfer(Date, Time, Id)
if (search !== "") {
window.sessionStorage.setItem(
"searchList",
JSON.stringify(
r.data
)
);
}
...
or use it how you are currently using it
Hope it helps

Setting a jsx element value to fetch call value

I'm making a custom jsx element. I want to set the element's value to data, that a fetch call returns:
const BoardPage = () => {
const id = useParams().id
fetch('http://localhost:8000/getBoardByID', {
headers: {
'Content-type': 'application/json'
},
method: 'POST',
body: JSON.stringify({ id: id })
}).then(response => response.json()).then(data => {
console.log(data)
return (
<div>
<h1>board #{data.id}</h1>
</div>
)
})
}
export default BoardPage
In console i see an object: {id: 31, board_content: '', width: 1223, height: 2323, user_privileges: '[]'}
But i get nothing as the output
You have to perform the request inside the useEffect hook.
const MyComponent = () => {
const id = useParams().id;
const [data, setData] = useState({});
React.useEffect(() => {
fetch("http://localhost:8000/getBoardByID", {
headers: {
"Content-type": "application/json",
},
method: "POST",
body: JSON.stringify({ id: id }),
})
.then((response) => response.json())
.then((data) => {
setData(data);
});
}, []);
return (
<div>
<h1>board #{data?.id}</h1>
</div>
);
};

How can I update quantity of the product in UI, immediately at the time of updating the database?

const [product, setProduct] = useState({});
useEffect(() => {
const url = `http://localhost:5000/product/${id}`;
fetch(url)
.then(res => res.json())
.then(data => setProduct(data))
}, [id]);
const handleDeliveredBtn = id => {
const newQuantity = parseInt(quantity) - 1;
const updatedQuantity = { newQuantity };
const url = `http://localhost:5000/product/${id}`;
fetch(url, {
method: 'PUT',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify(updatedQuantity)
})
.then(res => res.json())
.then(data => {
toast('Product delivered successfully.');
})
};
I want to show the updatedQuantity in my UI. Quantity is updated at database. But, without reloading the page, I can't see any changes that happen in my UI.
You need to use setProduct to cause a render. React components only render whenever there is a change in the state or props, which in your case is invoked by the setProduct.
const [product, setProduct] = useState({});
useEffect(() => {
const url = `http://localhost:5000/product/${id}`;
fetch(url)
.then(res => res.json())
.then(data => setProduct(data))
}, [id]);
const handleDeliveredBtn = id => {
const newQuantity = parseInt(quantity) - 1;
const updatedQuantity = { newQuantity };
const url = `http://localhost:5000/product/${id}`;
fetch(url, {
method: 'PUT',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify(updatedQuantity)
})
.then(res => res.json())
.then(data => {
toast('Product delivered successfully.');
setProduct(data) // add setProduct
})
};
You might want to make a shallow copy instead for performance / unnessecary renders but for the sake of example I just added setProduct(data).
You need one more useState hook to display updated value in your UI. checkout below code:
const [product, setProduct] = useState({});
const [updatedQuantity, setUpdatedQuantity] = useState({});
useEffect(() => {
const url = `http://localhost:5000/product/${id}`;
fetch(url)
.then(res => res.json())
.then(data => setProduct(data))
}, [id]);
const handleDeliveredBtn = id => {
const newQuantity = parseInt(quantity) - 1;
setUpdatedQuantity(newQuantity);
const url = `http://localhost:5000/product/${id}`;
fetch(url, {
method: 'PUT',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify(updatedQuantity)
})
.then(res => res.json())
.then(data => {
toast('Product delivered successfully.');
})
};
now you can use updatedQuantity as a current data in your UI.

Stop react redirecting before API call has finsished

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...
});
};

How to set fetch data to text field in react-native function component

I am learning react-native and have a question about fetching data and passing them to a text component.
I fetched my data from my node.js back-end but don't know how to pass this data to component. Below is the code that i have tried so far.
const TableView = () => {
const [details, setDetails] = useState('');
const getUserData = async () => {
fetch('https://----.herokuapp.com/getIncomePerUser', {
method: 'post',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
email: data,
month: value,
}),
})
.then(response => response.json())
.then(response => {
console.log('Test');
console.log(response);
const array = response;
for (const i of array) {
const total = i.total;
setDetails(total);
console.log(total);
}
})
.catch(err => {
console.log(err);
});
});
};
useEffect(() => {
getUserData();
}, []);
return (
<Text Value={details}></Text> //I need to set my fetch data this text component
)
}
if you have an array of values and you want to show them you can use:
const TableView = () => {
const [details, setDetails] = useState('');
const getUserData = async () => {
fetch('https://----.herokuapp.com/getIncomePerUser', {
method: 'post',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
email: data,
month: value,
}),
})
.then(response => response.json())
.then(response => {
setDetails(response.map(r => r.total));
})
.catch(err => {
console.log(err);
});
});
};
useEffect(() => {
getUserData();
}, []);
return (<>
{details.map((d, i) => <Text key={i}>{d}</Text>)}
</>)
}
if you have a single value just replace your text component with:
<Text>{details}</Text>

Resources