data is not fetching more than one time Reactjs - javascript

I have two buttons (tab) and i want to fetch different data after click on these tabs
code is working one time(after refresh page) but if i again click on tab then nothing displaying
Here is my current code
const Post = ({ post, blogs }) => {
// for latest data
const [students2,setStudents2] = useState({
data: [], //change string to array
loading: true
})
const handleClick2 = async() => {
var spath=router.asPath;
const response = await axios.get(`https://xxxxxxxxx/xxxxxxxxxx`)
setStudents2({
data: response.data,
loading: false
})
}
}
// for pinned
const [students,setStudents] = useState({
data: [], //change string to array
loading: true
})
const handleClick = async() => {
var spath=router.asPath;
const response = await axios.get(`https://xxxxxxxxx/xxxxxxxxxx`)
setStudents({
data: response.data,
loading: false
})
}
}
<a className="nav-link active" onClick={(e) => handleClick5(e)}>Newest</a>
<a className="nav-link" onClick={(e) => handleClick2(e)}>pined</a>
for fetch data i am using following code
{students2.data?.length > 0 &&
students2.data.map((blog) => (
// fetch pinneddata
}
{students.data?.length > 0 &&
students.data.map((blog) => (
// fetch latest data
}

Related

React State is not showing when used outside console log

I'm using antd with react to upload an image to each of my facilities.
The uploading is working, but I can't seem to get the preview from the previous image to show up where it should, by pulling the existing image from the database.
What happens is that it will only show the new image, after it has been uploaded via drag and drop but not the previous one stored in the database. I'm pulling the url of the previous image with the const "testing" and I can log it and it will show inside the console but it will not show when I use it in the setFileList const. What am I missing here?
export function FacilityUpdate() {
const navigate = useNavigate()
const { id } = useParams()
const [facility, setFacility] = useState(null)
const accessToken = useSelector((state) => state.tokens.value.accessToken);
const [loadingFacility, setLoadingFacility] = useState(false)
const [loading, setLoading] = useState(false)
const dispatch = useDispatch();
useEffect(() => {
if (facility && !facility.is_owner) {
navigate('/facilities')
}
return () => null
})
useEffect(() => {
setLoadingFacility(true)
function fetchFacility() {
axios.get(API.facilities.retrieve(id), {
headers: {
"Authorization": `Bearer ${accessToken}`
},
withCredentials: true,
})
.then(res => {
setFacility(res.data)
})
.finally(() => {
setLoadingFacility(false)
})
}
fetchFacility()
return () => null
}, [id, accessToken])
const testing = facility && (facility.mainimage)
console.log(testing)
const [fileList, setFileList] = useState([
{
uid: '-1',
name: testing,
status: 'done',
//This is where the preview image gets loaded from the database:
url: testing,
},
]);
const onUploadDraggerChange = ({ fileList: newFileList, file: resp }) => {
setFileList(newFileList);
if (!resp || !resp.response || !resp.response.mainimage) {
return;
}
message.success("Updated facility picture")
};
const uploadDraggerrops = {
name: 'mainimage',
action: API.facilities.update(id),
method: 'PATCH',
listType: "picture-card",
maxCount: 1,
onChange: onUploadDraggerChange,
fileList: fileList,
headers: {
"Authorization": `Bearer ${accessToken}`
},
withCredentials: true,
};
The problem with your code might come from this line on onUploadDraggerChange:
setFileList(newFileList);
Before updating the state of fileList, fileList is an array with an element that contains that previous picture. When you call onUploadDraggerChange you are erasing the stored content and replacing it with the new one. Maybe you want to push it to add to the array?
setFileList([...fileList, newFileList]);
This way, the first element is the one fetched and the consequent ones from the draggerUpload.
Any case, it looks like the structure of your state should look like
const [facility, setFacility] = useState(null)
const [fileList, setFileList] = useState([]);
useEffect(() => {
if (facility && !facility.is_owner) {
navigate('/facilities')
}
return () => null
})
useEffect(() => {
setLoadingFacility(true)
function fetchFacility() {
axios.get(API.facilities.retrieve(id), {
headers: {"Authorization": `Bearer ${accessToken}`},
withCredentials: true,
})
.then(res => {
setFacility(res.data)
res && (res.mainimage) {
setFileList([...filelist, {
uid: 'some-random-id',
name: testing,
status: 'done',Ï
url: res.mainimage
}])
})
.finally(() => {
setLoadingFacility(false)
})
}
fetchFacility()
return () => null
}, [id, accessToken])

MongoDB keeps returning one less value than intended value

I am currently working on a blog project where I have to enable a "liking" feature on my blog website. I have enabled the liking feature, however, whenever I test the liking feature with my MongoDB, the response I get is always a like that is one less than the intended value. For example, if I give a blog a like, that already has 4 likes, I get back a document only showing the 4 likes and not the updated document with the new 5 likes.
Here is my frontend code that deals with the "liking" feature:
import axios from "axios"
import { useEffect, useState } from "react"
import blogService from '../services/blogs'
const baseUrl = '/api/blogs'
const Blog = ({blog}) => {
const [checker, setChecker] = useState(false)
const [blogLikes, setBlogLikes] = useState(0)
const [updatedBlog, setUpdatedBlog] = useState({})
const buttonText = checker ? 'hide' : 'view'
useEffect(() => {
setUpdatedBlog({
user: blog.user?.id,
likes: blogLikes,
author: blog.author,
title: blog.title,
url: blog.url
})
}, [blogLikes])
const blogStyle = {
paddingTop: 10,
paddingLeft: 2,
border: 'solid',
borderWidth: 1,
marginBottom: 5
}
const handleLike = async (e) => {
e.preventDefault()
setBlogLikes(blogLikes + 1)
const response = await blogService.update(blog?.id, updatedBlog)
console.log(response)
}
return (
<>
{buttonText === "view" ?
<div style={blogStyle}>
{blog.title} {blog.author} <button onClick={() => setChecker(!checker)}>{buttonText}</button>
</div>
: <div style={blogStyle}>
{blog.title} {blog.author} <button onClick={() => setChecker(!checker)}>{buttonText}</button>
<p>{blog.url}</p>
likes {blogLikes} <button onClick={handleLike}>like</button>
<p>{blog.user?.username}</p>
</div>}
</>
)
}
export default Blog
Here is my backend code that deals with the put request of the "new" like:
blogsRouter.put('/:id', async (request, response) => {
const body = request.body
const user = request.user
console.log(body)
const blog = {
user: body.user.id,
title: body.title,
author: body.author,
url: body.url,
likes: body.likes
}
const updatedBlog = await Blog.findByIdAndUpdate(ObjectId(request.params.id), blog, { new: true })
response.json(updatedBlog)
})
Here is the specific axios handler for put request in another file within frontend directory:
const update = async (id, newObject) => {
const request = await axios.put(`${ baseUrl }/${id}`, newObject)
return request
}
State updates are asynchronous in react, because of that when your API call happens:
const handleLike = async (e) => {
e.preventDefault()
setBlogLikes(blogLikes + 1)
const response = await blogService.update(blog?.id, updatedBlog)
console.log(response)
}
The updatedBlog object still contains old data, not the updated one.
So try the following, change your handleLike function to this:
const handleLike = () => {
setBlogLikes(blogLikes + 1)
}
And add your API call in the useEffect:
useEffect(() => {
setUpdatedBlog({
user: blog.user?.id,
likes: blogLikes,
author: blog.author,
title: blog.title,
url: blog.url
});
blogService.update(blog?.id, {
user: blog.user?.id,
likes: blogLikes,
author: blog.author,
title: blog.title,
url: blog.url
}).then((response) => console.log(response));
}, [blogLikes]);

How to fix pagination first page load all data but onclick rest button load correctly in react

First part of my code:
const Inventory = () => {
const [products, setProducts] = useState([]);
const [pageCount,setPageCount] = useState(0);
//console.log(pageCount);
const [page,setPage] = useState(0);
const navigate = useNavigate();
useEffect(() => {
fetch(`http://localhost:3000/products?page=${page}`)
.then((res) => res.json())
.then((data) => setProducts(data));
}, [products,page]);
useEffect(()=>{
axios.get('http://localhost:3000/product-count')
.then((res) => {
const productCount = res?.data?.count;
//console.log("count product",count);
const pages = Math.ceil(productCount/6);
setPageCount(pages);
})
},[page])
Return section, this code will return pagination:
<div className="pagination">
{
[...Array(pageCount).keys()]
.map(number => <button key={number} className={page===number? 'selected': 'pagination'}
onClick={()=> setPage(number)}
>
{number+1}
</button>)
}
</div>
And this is the server-side code:
app.get("/products",async(req,res)=>{
const page = parseInt(req.query.page);
//console.log(page);
const q = {};
const cursor = productCollection.find(q);
let result;
if(page){
result = await cursor.skip(page * 6).limit(6).toArray();
}
else{
result = await cursor.toArray();
}
res.send(result);
})
// get product count
app.get("/product-count",async(req,res)=>{
const query = {};
const count = await productCollection.countDocuments(query);
res.json({count});
})
I want to load 6 data on the first load. But when data loads it displays all data. When I click the pagination button it works fine except the 1st button.
During the first load your front-end is sending page=0 to your backend.
In your server-side code you've the following statement: if (page)
But page will always be false when page=0, because 0 is a falsy value in javascript. So your statement always return the else block.
You need to change the statement to:
if (page !== undefined)

Put results of a Get request from axios to an array

I don't understand a very simple task, I made a request from a API with axios in react.
If I console log the res.data, is like 170 result of single objects on my console.
I need to convert all these result in a single array of objects.
It's a basic task but I don't understand how to do it.
The application is a Trello Clone.
I have a variable called board that has all the data and with this list request, I grab all the column the the trello and append to ListObjects [] in newBoardData (it's a clone of board)
Here is my code:
//Get Request
const getList = async (id) => {
try {
return await axios.get(`${ENDPOINT}/lists/${id}`);
} catch (err) {
console.log(err);
}
};
const [loading, setLoading] = useState(false);
// Use Effect for grab the data with the listId
useEffect(() => {
(async () => {
setLoading(true);
const res = await (getList(listId));
//Loading up the listObjects
const oldList = board.board.listObjects
const newList = []
const payload = res.data;
//Adding all the old values to the new list (except for the current payload id)
for(let obj of oldList){
if(obj._id !== payload._id) newList.push(obj)
}
//Adding the current payload id
newList.push(payload)
const data = {
...board,
board: {...board.board, listObjects: newList}
};
setList(res.data);
// Here I put the data objects with the new ListObjects Array
setBoardNew(data);
setLoading(false);
})();
}, []);
Here is the console log of the get request res.data:
console.log of res.data
here is the board object:
board object
You can saw that there is a spam of result with the current res.data in ListObjects
I'think it make a request for every card in every list.
thank you very much!
UPDATE:
I will explain how the app works:
I have a file called Board.js, where I make this call (in the console log I have two call if I have two columns):
try {
return await axios.get(`${ENDPOINT}/boards/${id}`);
} catch (err) {
console.log(err);
}
};
useEffect(() => {
(async () => {
setLoading(true);
const res = await (getUserBoard(match.params.id));
if (res) {
axios.defaults.headers.common['boardId'] = match.params.id;
} else {
delete axios.defaults.headers.common['boardId'];
}
const payload = { ...res.data, listObjects: [], cardObjects: [] };
const data = {
...state,
board: { ...state.board, ...payload },
};
setBoardData(data);
setLoading(false);
})();
}, []);
Then I send the props data to the file List.js
{board.board.lists.map((listId, index) => (
<List key={listId} listId={listId} index={index} board={board} />
The list file send the data to
card.js
{list.cards.map((cardId, index) => (
<Card key={cardId} cardId={cardId} list={list} index={index} board={boardNew} />
The logic is: There is the board(board.js), in the board there are the lists (column)(list.js) in the lists there are the cards (card.js)
I hope it's more clear.
simple use this approach to add your new id value into the array state.
this.setState({ myArray: [...this.state.myArray, 'new value'] }) //simple value
this.setState({ myArray: [...this.state.myArray, ...[1,2,3] ] }) //another array

ReactJS: Make select with result from two query

I'm trying to create a select in which I take datafrom two api, I compare these data and show the results in the select.
my select is a Paginate Select so I need to search if there are other data when i call API
const SelectAsyncPaginate = props => {
const [realmScelto, setRealmScelto] = useState(null);
const [listaRealm, setListaRealm] = useState([]);
useEffect(() => {
setRealmScelto(props.realmScelto);
}, [props.realmScelto]);
const loadOptions = async (searchQuery, loadedOptions, { page }) => {
const response = await fetch(
`${apiUrl}?page=${page}&size=20&deletedDate.specified=false${searchQuery.length > 3 ? `&appDesapplicazione.contains=${searchQuery}` : ''
}`
)
const response2 = await fetch(
`${apiUrlRealm}?page=${page}&size=20&deletedDate.specified=false`
)
const optionToShow = await response.json();
const optionToShow2 = await response2.json();
console.log("optionToShow1", optionToShow)
console.log("optionToShow2", optionToShow2)
const notPresent = optionToShow2.filter(ra => {
return !optionToShow.some(rua => rua.realm.id === ra.id && rua.user.perCod === props.persona.perCod.perCod);
});
setListaRealm(previousListRealm => [...previousListRealm, ...notPresent]);
console.log("listaRealm", listaRealm)
return {
options: listaRealm,
hasMore: listaRealm.length >= 1,
additional: {
page: searchQuery ? 2 : page + 1,
},
};
};
const onChange = option => {
if (typeof props.onChange === 'function') {
props.onChange(option);
}
};
return (
<AsyncPaginate
value={props.value}
loadOptions={loadOptions}
getOptionValue={option => option.realm.id}
getOptionLabel={option => option.realm.realmId}
onChange={onChange}
isSearchable={true}
placeholder="Seleziona Realm"
additional={{
page: 0,
}}
/>
);
};
If I use only one api call it works, the problem is when I call the second API because I have a loop of api calls and it not controll if there is another page and it never update the listaRealm
How can I do in your opinion??
What I would to obtain is like:
API call (apiUrl)
1.1 Check if there is another page
API call (apiUrlRealm)
2.2 Check if there is another page
Compare the two results to obtain result

Categories

Resources