useEffect call different API onClick - reactjs

I am working with useEffect and want to figure out how to call a different API when an onClick event happens. When my page loads the following is run:
useEffect(() => {
if (userData.user) {
axios
.get(`http://localhost:5000/reviews/reviews?email=${userData.user.email}`, userData)
.then((response) => {
console.log(response)
setReview(response.data)
});
}
}, [userData]);
however when a user selects an onClick event on the webpage, I want a different API to be called and for the data from the original request to disappear. Here is the second request I want to send:
axios
.get(`http://localhost:5000/reviews/reviews?reviewNumber=1`)
.then(response => {
console.log(response)
setallreviews(response.data)
})
Adding the page code here as requested:
return(
<div>
{userData.user ? (
<div>
<div>
<FeedbackNav />
</div>
<div>
<div>
{filterMode ? (
<div onClick={() => setFilterMode(false)}>
<h1 className='testing123'>My reviews and feedback</h1>
<p className='testing1234'>Reviews are reviews that you have provided on another project</p>
<p className='testing1234'>Feedback is feedback that others have provided on your own project</p>
<button className='rectangle' onClick={() => setFilterMode(false)}>
<img className='filterImage' src={Filter} />Filter
</button>
<ul className='filteroptions'>
<p className='allreviewsfeedback' onClick={() => {
setFilterMode();
getReviews();
}}>My reviews</p>
<p className='myfeedback' onClick={() => {
setFilterMode();
}}>My feedback</p>
</ul>
</div>
) : (
<div>
<h1 className='testing123'>My reviews and feedback</h1>
<p className='testing1234'>Reviews are reviews that you have provided on another project</p>
<p className='testing1234'>Feedback is feedback that others have provided on your own project</p>
<button className='rectangle' onClick={() => setFilterMode(true)}>
<img className='filterImage' src={Filter}/>
Filter
</button>
</div>
)}
</div>
<div className='testing1234'>
{allreviews.map(allreviews => (
<p key={allreviews._id}>{allreviews.review}</p>
))}
</div>
<div className='testing1234'>
{review.map(review => (
<p key={review._id}>{review.review}</p>
))}
</div>
</div>
</div>
) : (
<div>
<Landing />
</div>
)}
</div>
)
}
What is the best way to do this? Thank you!

You can do something like this:
const [clicked, setClicked] = useState(false);
const handleClick = () => {
setClicked(true);
};
useEffect(() => {
if (clicked) {
axios
.get(`http://localhost:5000/reviews/reviews?reviewNumber=1`)
.then(response => {
console.log(response)
setallreviews(response.data)
setReview(null);
});
} else if (userData.user) {
axios
.get(`http://localhost:5000/reviews/reviews?email=${userData.user.email}`, userData)
.then((response) => {
console.log(response)
setReview(response.data)
});
}
}, [userData]);
return (
<div>
some text...
<button onClick={handleClick}>Click!</button>
</div>
);

Listen to search params and call axios.get if search params changed.
const { search } = useLocation(); // import { useLocation } from 'react-router-dom';
useEffect(() => {
if (!search) return;
axios.get(`http://localhost:5000/reviews/reviews${search}`).then();
}, [search]);

Related

UseState value doesn't change when re-render in NextJs

I am creating a blog application on NextJs and on the page which displays posts by category i faced with a problem
i have a useState which contains all posts that i get from backend by category that i pass
The problem is when i click on the link which changes category of displayed posts i still got same posts on page, and to get actual useState value i have to reload page, how to fix it?
Here is full component
const News: FC<NewsCat> = ({ news, category }) => {
const [selectedCateg, setSelectedCateg] = useState(category);
//UseState with posts
const [postsList, setPostsList] = useState(news);
const [page, setPage] = useState(1);
const handleClick = (categ: string) => {
setSelectedCateg(categ);
};
return (
<div className={styles.wrap}>
<nav className={styles.categories}>
//Cetegory list
{list.map((i: string, index) => (
<Link href={"/category/" + listEng[index]} key={index}>
<button
className={styles.active}
onClick={() => handleClick(listEng[index])}
>
<h2>{i}</h2>
</button>
</Link>
))}
</nav>
<div className={styles.catTitle}>
<h1>{newsTranslate(selectedCateg)}</h1>
</div>
<div className={styles.mainBlock}>
{postsList.map((i: News) => (
<div key={i._id} className={styles.normal_card}>
<div className={styles.normal_card_img}>
<Link href={"/news/" + i._id}>
<img src={i?.image} alt="" />
</Link>
<div className={styles.desc}>
<div className={styles.up_desc}>
<Link href={"/category/" + category}>
<h6>{newsTranslate(i.category)}</h6>
</Link>
<h6>| {moment(i.createdAt).format("LLL")}</h6>
</div>
<Link href={"/news/" + i._id}>
<h2 className={styles.titleDesc}>
{i.title?.length > 150
? `${i.title?.substring(0, 90)}...`
: i.title}
</h2>
</Link>
</div>
</div>
<div className={styles.normal_card_desc}>
<h4>{moment(i.createdAt).format("LLL")}</h4>
</div>
</div>
))}
</div>
<div className={styles.loadMoreButton}>
<button
onClick={async () => {
setPage(page + 1);
console.log(page);
const getNextPosts = await axios.get(
"http://localhost:3000/api/category/" + category,
{
params: {
page: page,
},
}
);
setPostsList([...postsList, ...getNextPosts.data]);
}}
>
LoadMore
</button>
</div>
</div>
);
};
export default News;
export const getServerSideProps: GetServerSideProps = async ({
params,
}: any) => {
const res = await axios.get(
`http://localhost:3000/api/category/${params.category}`,
{
params: {
page: 1
}
}
);
return {
props: {
news: res?.data,
category: params?.category,
},
};
};
I know that i can fix it like this:
useEffect(() => {
setPostsList(news)
}, [news])
but in my opinion its not the best way
postsList will only change value when you call setPostsList (except for the initial value which you're passing in on first load).
So after the category is changed, you'll need to fetch the posts from the API and call setPostsList (similar to how you are doing on page change)

React Owl Carousel 2.3.3 - I loose dynamic data after refreshing page. Working fine on local data

I am using json-server and fetching data using fetch. First time I get data properly in an Owl Carousel and the slider works fine but after when I refresh the page all my dynamic data wipe out. Still my carousel slides but with no data. Also I have attached a jquery script https://code.jquery.com/jquery-3.2.1.slim.min.js in index.html.
I am loosing my Owl Carousel Dynamic Data which I am using through map method in the Owl Carousel Component. Below is the code where I am using my slider. Please help me to find where I am doing wrong. Thank You.
---------------
<<<<<- Below code is MainSlider.js ->>>>>
import React, { useReducer, useEffect } from "react";
import OwlCarousel from "react-owl-carousel";
import "owl.carousel/dist/assets/owl.carousel.css";
import { mainSliderReducer } from "../reducers/mainSliderReducer";
const API = "http://localhost:8000/mainSlider";
const initialState = {};
const MainSlider = () => {
const [state, dispatch] = useReducer(mainSliderReducer, initialState);
const { data } = state;
useEffect(() => {
getData();
}, []);
const getData = () => {
fetch(API)
.then((res) => {
if (res.ok) {
return res.json();
} else {
console.log("DATA NOT FOUND. SOME ERROR");
throw new Error("ERROR FETCHING DATA");
}
})
.then((data) => dispatch({ type: "GET_MAINSLIDER_DATA", payload: data }))
.catch((err) => console.log(err));
};
console.log(data);
return (
<>
<OwlCarousel className="owl-theme" loop margin={10} nav>
{data ? (
data.map((item) => {
const { id, heading, description, img, smallHeading } = item;
return (
<section key={id} className="dvMainSlider">
<div className="item bg bgcolor1 pb-md-5 pt-md-4 py-xl-0 h-100vh h-sm-auto h-xl-100vh">
<div className="container">
<div className="row slideInfo h-xl-100vh align-items-xl-center">
<div className="col-md-6 text-center">
<img
src={img}
className="img-fluid d-inline-block"
alt=""
/>
</div>
<div className="col-md-6 pt-lg-5 pt-xl-0 description">
<h1 className="text-white">{heading}</h1>
<h4 className="text-white">{smallHeading}</h4>
<p className="text-white">{description}</p>
<a href="--" className="btn btnPrimary mb-3 mt-sm-3">
Shop More
</a>
</div>
</div>
</div>
</div>
</section>
);
})
) : (
<h1>"SLIDE NOT FOUND"</h1>
)}
</OwlCarousel>
</>
);
};
export default MainSlider;
<<<<<- Below code is mainSliderReducer.js ->>>>>
export const mainSliderReducer = (state, action) => {
console.log(state, action);
switch (action.type) {
case "GET_MAINSLIDER_DATA":
return { ...state, data: action.payload };
default:
return state;
}
};
Hey I found my own question's answer and i found the way which i am sharing to you all. Just check if data is available then only you load the Owl Carousel Component. Check the code below for better understanding.
{data && (
<OwlCarousel {...options}>
{data.map((item) => {
const { id, heading, description, img, smallHeading } = item;
return (
<section key={id} className="dvMainSlider">
<div className="item bg bgcolor1 pb-md-5 pt-md-4 py-xl-0 h-100vh h-sm-auto h-xl-100vh">
<div className="container">
<div className="row slideInfo h-xl-100vh align-items-xl-center">
<div className="col-md-6 text-center">
<img
src={img}
className="img-fluid d-inline-block"
alt=""
/>
</div>
<div className="col-md-6 pt-lg-5 pt-xl-0 description">
<h1 className="text-white">{heading}</h1>
<h4 className="text-white">{smallHeading}</h4>
<p className="text-white">{description}</p>
<a href="--" className="btn btnPrimary mb-3 mt-sm-3">
Shop More
</a>
</div>
</div>
</div>
</div>
</section>
);
})}
</OwlCarousel>
)}

How to access item object outside "return" in react?

I need some help...
I'm trying to access my object in a function to delete the object in my backend:
import React, { useState, useEffect } from 'react';
function AllMeetupsPage() {
const [isLoading, setIsLoading] = useState(true);
const [loadedMeets, setloadedMeets] = useState([]);
useEffect(() => {
fetch('http://localhost:4000/').then(response => {
return response.json();
}).then(data => {
setIsLoading(false)
setloadedMeets(data)
})
}, [])
if (isLoading) {
return (
<p>Loading...</p>
)
}
if (loadedMeets.length === 0) {
return (
<p className="container"> NO DATA...</p>
)
}
return (
<section className="container">
<div>
{loadedMeets.map((item) => {
return <div teste='ASDAUSD' key={item._id} className='meetUpCard'>
<img className="meetUpImg" src={item.imageUrl} alt="" />
<div className="meetupDetails">
<h4>{item.title}</h4>
<small>{item._id}</small>
<p><i className="fas fa-info-circle"></i> {item.description}</p>
<div className='meetupActions'>
<button className='btn btn-details'>Details</button>
<button className='btn btn-delete' onClick={handleDelete}><i className="fas fa-trash-alt"></i></button>
</div>
</div>
</div>
})}
</div>
</section>
)
}
export default AllMeetupsPage
My delete func:
function handleDelete(item) {
fetch('http://localhost:4000', {
method: 'DELETE',
body: JSON.stringify(item)
})
}
The problem is that I cant access the item object to send to my backend and delete it... How can I access this object? I mean, the button is part of the object it self, I don't understand why I cant pass to my function...
Thank you very much
You have to pass the item to your handle function, in order to know which item you want to delete.
<button className='btn btn-delete' onClick={() => handleDelete(item)}>

Toggle specific div (id) within a react component

I have a site built with post-components to show articles in a feed. Inside the component, I have a button that opens a modal onClick. I use useState to toggle on the modal which works perfectly fine. The problem is that since the toggle is put on the modal-div inside the component.. every single post modal opens whenever I click one of the buttons. I want to open only the targeted post modal (with the sam post id as the button I’m clicking). I can’t figure out how to do this…in react.
const [toggle, setToggle] = useState (true);
const toggler = () => {
setToggle(prev => !prev)
}
...
return (
<section className="posts">
{data.allMarkdownRemark.edges.map((edge) => {
return (
<div className="post">
<div className="postDescrip">
<h2 className="postTitle">{edge.node.frontmatter.title}</h2>
<h2 className="name">{edge.node.frontmatter.name}</h2>
<button className="readMoreBtn" onClick={toggler}>{toggle ? <h2 className="readMore">Read more</h2> : <h2 className="readMore">Read less</h2>}
</button>
</div>
<Img className="postImg" fluid={edge.node.frontmatter.featuredImage.childImageSharp.fluid} />
<div className={toggle ? 'hide' : 'postCopy'} >
<Close close={toggler} />
<h3>{edge.node.frontmatter.details}</h3>
<div className="copy" dangerouslySetInnerHTML= {{__html: edge.node.html}}></div>
<h4>Read the full article in Issue One</h4>
</div>
</div>
)}
)}
</section>
)
}
export default Posts;
After trying suggested solution using object instead on bolean. I now receive this error message
[Error message][1]for the following code:
const [toggles, setToggles] = useState ({});
let id;
const createToggler = (id) = () => {
setToggles(prev => { [id] : !prev[id] })
// setToggle(prev => { ...prev, [id]: !prev[id] }) // or support multi modal at same time. but I think you don't want it.
}
const data = useStaticQuery(graphql`
query {
allMarkdownRemark (
sort: { order: DESC, fields: [frontmatter___date] }
){
edges {
node {
frontmatter {
id
title
name
details
featuredImage {
childImageSharp {
fluid(maxWidth: 800) {
...GatsbyImageSharpFluid
}
}
}
}
html
fields {
slug
}
}
}
}
}
`)
return (
<section className="posts">
{data.allMarkdownRemark.edges.map((edge) => {
const id = edge.node.frontmatter.id;
const toggle = toggles[id];
const toggler = createToggler(id);
return (
<div className="post" id={edge.node.frontmatter.id}>
<div className="postDescrip">
<h2 className="postTitle">{edge.node.frontmatter.title}</h2>
<h2 className="name">{edge.node.frontmatter.name}</h2>
<button className="readMoreBtn" onClick={toggler}>{toggle ? <h2 className="readMore">Read more</h2> : <h2 className="readMore">Read less</h2>}
</button>
</div>
<Img className="postImg" fluid={edge.node.frontmatter.featuredImage.childImageSharp.fluid} />
<div className={toggle ? 'hide' : 'postCopy'} id={edge.node.frontmatter.id}>
<Close close={toggler} />
<h3>{edge.node.frontmatter.details}</h3>
<div className="copy" dangerouslySetInnerHTML= {{__html: edge.node.html}}></div>
<h4>Read the full article in Issue One</h4>
</div>
</div>
)}
)}
</section>
)
}
export default Posts;
[1]: https://i.stack.imgur.com/VhIYF.png
like this.
use a object instead of a single boolean.
const [toggles, setToggles] = useState ({});
const createToggler = (id) = () => {
setToggle(prev => { [id]: !prev[id] }) // atmost one id is true. others is undefine or false.
// setToggle(prev => { ...prev, [id]: !prev[id] }) // or support multi modal at same time. but I think you don't want it.
}
...
return (
<section className="posts">
{data.allMarkdownRemark.edges.map((edge) => {
const id = ... // get your id form edge.
const toggle = toggles[id];
const toggler = createToggler(id);
return (
<div className="post">
<div className="postDescrip">
<h2 className="postTitle">{edge.node.frontmatter.title}</h2>
<h2 className="name">{edge.node.frontmatter.name}</h2>
<button className="readMoreBtn" onClick={toggler}>{toggle ? <h2 className="readMore">Read more</h2> : <h2 className="readMore">Read less</h2>}
</button>
</div>
<Img className="postImg" fluid={edge.node.frontmatter.featuredImage.childImageSharp.fluid} />
<div className={toggle ? 'hide' : 'postCopy'} >
<Close close={toggler} />
<h3>{edge.node.frontmatter.details}</h3>
<div className="copy" dangerouslySetInnerHTML= {{__html: edge.node.html}}></div>
<h4>Read the full article in Issue One</h4>
</div>
</div>
)}
)}
</section>
)
}
export default Posts;
I solved my problem like this
import React, {useState} from "react"
import Img from "gatsby-image"
import './posts.css';
import cancel from '../images/cancel.png'
const Post = ({title, name, id, image, details, html}) => {
const [toggle, setToggle] = useState (true);
const toggler = () => {
setToggle(prev => !prev)
}
const selectPost= (event) =>{
let id = event.target.id,
postCopy = document.getElementById('hide' + id);
toggler.call(postCopy);
}
return (
<div className="post">
<div className="postDescrip">
<h2 className="postTitle">{title}</h2>
<h2 className="name">{name}</h2>
<button className="readMoreBtn" onClick={selectPost}>{toggle ? <h2 id={id} className="readMore">Read more</h2> : <h2 id={id} className="readMore">Read less</h2>}
</button>
</div>
<Img className="postImg" fluid={image} />
<div id={'hide' + id} className={toggle ? 'hide' : 'postCopy'} >
<button aria-label="Close" onClick={selectPost} className="closeBtn">
<img alt="close-button" src={cancel}/>
</button>
<h3>{details}</h3>
<div className="copy" dangerouslySetInnerHTML= {html}></div>
<h4>Read the full article in Issue One</h4>
</div>
</div>
)
}
export default Post;

Async/await React: objects are not valid, [object promise]

It's my first project working with React, and I'm fetching an API. I'm trying to pass on the data but it keeps giving me the same error however I do it.
Also, I can log the data in the async function addTrade, but it logs twice for some reason?
fetch:
async function asyncData() {
const response = await fetch('https://api.pokemontcg.io/v1/cards?setCode=base1');
const data = await response.json();
return data;
}
my render function:
const addTrade = async () => {
const pokemonList = await asyncData();
const cards = pokemonList.cards;
console.log(cards);
return <>
<div className='add-trade-container'>
<div className='trade-add-window'>
<div id={1} onClick={e => handleActiveTab(e)} className={tradeBoard.activeTab === '1' ? 'trade-tab trade-tab-active' : 'trade-tab'}>
<span className='trade-tab-title'>Has</span>
{tradeBoard.has.map(has =>
<>
<div className={tradeBoard.activeTab === '1' ? 'window window-active' : 'window'}>{has.content}</div>
</>
)}
</div>
<img className='divider' src='./src/assets/img/trade-icon.svg' width='30' height='30'></img>
<div id={2} onClick={e => handleActiveTab(e)} className={tradeBoard.activeTab === '2' ? 'trade-tab trade-tab-active' : 'trade-tab'}>
<span className='trade-tab-title'>Wants</span>
{tradeBoard.wants.map(wants =>
<>
<div className={tradeBoard.activeTab === '2' ? 'window window-active' : 'window'}>{wants.content}</div>
</>
)}
</div>
</div>
<article className='list'>
<label className='search-label' htmlFor='search'>Search a Pokémon
<input className='search-field' type='text' id='search'></input>
</label>
<div className='list-grid'>
{cards.map((card, index) =>
<div onClick={() => handleClickContent(<PokeItem pokemon={card} index={index}/>)} key={index}>
<PokeItem pokemon={card} index={index}/>
</div>
)}
</div>
</article>
<button onClick={handleSeedClick} className='button-add'>Add a trade</button>
</div>
</>;
};
App:
const App = () => {
return useObserver(() => (
<>
{addTrade()}
<div className='trades'>
{showTrades()}
</div>
</>
));
};
const roottype = document.getElementById('root');
const headtype = document.getElementById('header');
ReactDOM.render(<App />, roottype);
ReactDOM.render(<Header />, headtype);
you need to use react hooks for this
first you need to import useState, useCallback from react library like this import React, { useState, useCallback } from "react";
then use useEffect like this:
const addTrade = async () => {
const [cards,setCards] = useState(null)
useEffect(() => {
async function getData() {
try {
const pokemonList = await asyncData();
const cardsList = pokemonList.cards;
setCards(cardsList);
console.log(cardsList);
} catch (error) {
console.log(error);
}
}
getData();
}, [cards]);
return <>
<div className='add-trade-container'>
<div className='trade-add-window'>
<div id={1} onClick={e => handleActiveTab(e)} className={tradeBoard.activeTab === '1' ? 'trade-tab trade-tab-active' : 'trade-tab'}>
<span className='trade-tab-title'>Has</span>
{tradeBoard.has.map(has =>
<>
<div className={tradeBoard.activeTab === '1' ? 'window window-active' : 'window'}>{has.content}</div>
</>
)}
</div>
<img className='divider' src='./src/assets/img/trade-icon.svg' width='30' height='30'></img>
<div id={2} onClick={e => handleActiveTab(e)} className={tradeBoard.activeTab === '2' ? 'trade-tab trade-tab-active' : 'trade-tab'}>
<span className='trade-tab-title'>Wants</span>
{tradeBoard.wants.map(wants =>
<>
<div className={tradeBoard.activeTab === '2' ? 'window window-active' : 'window'}>{wants.content}</div>
</>
)}
</div>
</div>
<article className='list'>
<label className='search-label' htmlFor='search'>Search a Pokémon
<input className='search-field' type='text' id='search'></input>
</label>
<div className='list-grid'>
{cards.map((card, index) =>
<div onClick={() => handleClickContent(<PokeItem pokemon={card} index={index}/>)} key={index}>
<PokeItem pokemon={card} index={index}/>
</div>
)}
</div>
</article>
<button onClick={handleSeedClick} className='button-add'>Add a trade</button>
</div>
</>;
};

Resources