React state setting timing for conditional rendering - reactjs

Currently, I am working on a simple React Exercise.
The I am trying to conditionally render a certain part of the jsx based on a certain state.
Basically, my code looks like this
const ShopList = (props) => {
const [isLoading, setIsLoading] = useState(false)
const [isEnd, setIsEnd] = useState(false)
const handleButtonClick = ()=>{
setIsLoading(true)
axios.get('https://codingapple1.github.io/shop/data2.json')
.then((result)=>{
setTimeout(()=>props.addData(result.data),2000)
})
.then(()=>{
setIsEnd(true)
})
.catch((e)=>{
console.log(e)
setIsLoading(false)
})
}
return(
<div className="container">
<div className="row">
{props.shoes.map((shoe,i) => (
<Product shoe={shoe} ind={i+1} key={shoe.id}/>
))}
</div>
{isLoading && <h3>Loading....</h3>}
{!isEnd && <button className="btn btn-light" onClick={handleButtonClick}>More Items</button>}
</div>
)
}
export default ShopList;
The thing is that I am having trouble locating my setIsLoading(false) so that I can hide the <h3>Loading...</h3> after two seconds.
In which part of the handleButtonClick function should I put setIsLoading(false)?

Answering your question, you most likely need to hide "Loading" in both cases:
if the request was successful and not.
So you could do this in the finally section like this:
axios.get(...)
.then(...)
.catch(...)
.finally(() => setIsLoading(false));

Related

stateful never[] array is still being able to assign data

I know that when passing an empty array to useState hook we should also provide the proper type, otherwise typescript would infer never[].
The following is something I did before knowing that and by my surprise is working:
It's a component intended to fetch some data, that data is of type any and will be stored in loadedUsers, which has a type of never[].
const AllUsers: FC<AllUsersProps> = () => {
const [isLoading, setIsLoading] = useState(true);
const [loadedUsers, setLoadedUsers] = useState([]);
useEffect(() => {
UserService.getAllUsers()
.then((response) => response.json())
.then((data) => {
console.log("users after retrieving data", data);
setIsLoading(false);
setLoadedUsers(data);
});
}, []);
Then I use loadedUsers to render a simple view
if (isLoading) {
return (
<section>
<p>Loading users</p>
</section>
);
}
return (
<div className="row">
<div className="col">
<h3>Users table</h3>
<UserTable users={loadedUsers} />
</div>
<div className="col">
<h3>Find user by id</h3>
<UserSearch />
</div>
</div>
);
};
Why am I not getting any errors during compilation? even in vscode there is no warning message

how to make make a condition: if you just went to the page, then apply one dispath, and if you clicked on the div - apply dispath with another method

please help: I have a page with all movies rendered, I want to display an already filtered list of movies when I click on the div. That is, make a condition: if i just went to the page, i apply one dispath, and if i clicked on the div - apply dispath with another method
const {movies} = useSelector( state => state.movies);
const dispatch = useDispatch();
const [query, setQuery] = useSearchParams();
const {genres} = useSelector(state => state.genres);
useEffect(() => {
dispatch(movieActions.getAllMovies({page:query.get('page')}))
}, [dispatch,query])
useEffect(() => {
dispatch(genresActions.getAllGenres())
},[]);
const idg = (e) =>{
console.log(e)
}
return (
<div className={'filmBox'}>
<div className={'pag'}>
<PaginationComponent query={query} setQuery={setQuery}/>
</div>
<div className={'movgen'}>
<div className={'genreButtons'}>
<div>{genres.map(genre => <div id={genre.id} key={genre.id} onClick={()=>idg(genre.id)} className={'genreButton'}>
{genre.name}
</div>)}</div>
</div>
<div className={'moviesBox'}>
{
movies?.map(movie =><MoviesListCard key={movie.id} movie={movie}/> )
}
</div>

Cant get Spinner to work in React hook while waiting for API response

I am trying to get the spinner to load while waiting for API response.
I have tried several approaches but non seem to be working
I am using the react-spinner library
I set loading to true even before the API call, but still not showing.
I know I have to set it to false once the API call is successful, but I don't know what I am doing wrong that is not making the spinner to work
import React, { useState, useEffect } from "react";
import AuthService from "../../../services/auth.service";
import UserService from "../../../services/user.service";
import { BarLoader } from 'react-spinners'
function StatusTransactions() {
const [transactions, fetchTransactions] = useState([]);
const [loading, setLoading] = useState(false);
const [message, setMessage] = useState("");
const currentUser = Service.getUser();
useEffect(() => {
const getTransactions = () => {
setLoading(true)
UserService.getPendingTransactions(currentUser.user._id).then(response => {
fetchTransactions(response.data);
console.log(response.data)
}, (error) => {
const _content =
(error.response && error.response.data) ||
error.message ||
error.toString();
fetchTransactions(_content);
}
).catch(e => {
});
};
getTransactions();
}, []);
return (
<div className="content">
<ul className="dashboard-box-list user-dasboard-box">
{
transactions ? <BarLoader loading={loading} /> :
transactions.map(transaction => {
return (
<li key={transaction._id}>
<div className="invoice-list-item">
<strong>Professional Plan</strong>
<ul>
<li><span className="unpaid">{transaction.transactionStatus}</span></li>
<li>{transaction.TransactionBin}</li>
<li>Date: 12/08/2019</li>
</ul>
</div>
{/* <!-- Buttons --> */}
<div className="buttons-to-right">
Finish Payment
</div>
</li>
)
})}
</ul>
</div>
);
}
export default StatusTransactions;
I guess you should set size prop here "" as shown in the package documntation
your transaction state starts with an empty array ; which has logical value of true ,so transactions ? <BarLoader loading={loading} /> : seems to always pass BarLoader.
I finally solve it with suggestions from contributors.
I guess the BarLoader is not ok.
I tried ClipLoader like this It works.
loading ? <ClipLoader loading={loading} size={150} /> :
transactions.map(transaction => {
return (

Build a dropdown with an eventHandler. How to structure hooks + eventhandler

I'm building a simple dropdown with react and functional components. On strange behavior, I've run into is the way we have to think about conjures and state. This is a simplified version of my component:
export default function App() {
const [show, setShow] = useState(false);
const selectElement = useRef(null);
const handleToggle = (e) => {
if (selectElement) {
if (!selectElement.current.contains(e.target)) {
setShow(!show);
}
}
};
useEffect(() => {
document.addEventListener("click", handleToggle, false);
return () => document.removeEventListener("click", handleToggle, false);
}, []);
return (
<div className="App">
<div ref={selectElement} className="comp">
<h1 onClick={() => setShow(!show)}>Select</h1>
{show && (
<div>
<div>Inner 1</div>
<div>Inner 2</div>
</div>
)}
</div>
</div>
);
}
This component behaves wrong and it's not possible to toggle the dropdown correctly. The effect handler is registered on the first render and encloses the state of the first render (if I'm not wrong here). The registered function will not receive state updates. This is causing the error.
I'm not really sure what's the best way to fix this. Currently, I decided to simply remove the dependency array from the useEffect hook so that the effect handler is created and destroyed on every render/cleanup.
I've also created a Sandbox so my issue becomes more tangible.
I think this code will help you to solve your problem.
export default function App() {
const [show, setShow] = useState(false);
const selectElement = useRef(null);
const handleToggle = (e) => {
if (selectElement) {
if (!selectElement.current.contains(e.target)) {
setShow(false);
document.removeEventListener("click", handleToggle, false);
}
}
};
const handleClick = (e) => {
setShow(true)
document.addEventListener("click", handleToggle, false);
};
return (
<div className="App">
<div ref={selectElement} className="comp">
<h1 onClick={handleClick}>Select</h1>
{show && (
<div>
<div>Inner 1</div>
<div>Inner 2</div>
</div>
)}
</div>
</div>
);
}

Conditional rendering of React component if json key exists

I am trying to conditionally render a component with bad results. I have read many tutorials and Stack Overflow questions but I can't get this work. Could you help me?
The conditional component is a data visualization geographical map which should be rendered only when a fetched json file has "code" key. In other words I have dozens of jsons and some of them include geo map information but not all. I have been trying boolean and different kind of ternary operators in jsx but every time when mapless item is clicked in sidebar React tries to render Map child component and gives an error that "code" (key) is undefined. What could be reason for that? Below is my code:
App.js
function App() {
const [files, setFiles] = useState([]);
const [items, setItems] = useState([]);
const [product_id, setProduct_id] = useState(13);
const [mapCode, setMapcode] = useState(0);
useEffect(() => {
fetch("/sidebar")
.then((res) => res.json())
.then((data) => {
setItems(data);
});
}, []);
useEffect(() => {
fetch(`/data/${product_id}`)
.then((res) => res.json())
.then((data) => {
setFiles(data);
if ("code" in data[0]) setMapcode(1);
else setMapcode(0);
console.log(mapCode);
});
}, [product_id]);
function HandleSelection(e) {
setProduct_id(e);
}
Inside useEffect if fetched product data includes "code" key I change mapCode every time an item (product) is clicked in sidebar. console.log(mapCode) gives right kind of results.
Below is the essential code inside return() of App.js. There are couple of ways I have tried to get the conditional rendering work.
<div className="col-6">
<Files files={files} />
</div>
<div className="col-3">
{/*Boolean(mapCode) && <Map files={files} />*/}
{/*mapCode === true && <Map files={files} />*/}
mapCode === true ? <Map files={files} /> : <div>No map</div>
</div>
I have been wondering if useEffect is the right place to use setMapcode(0) and setMapcode(1)?
First you should set a boolean value to isMapCode instead of a number:
const [isMapCode, setIsMapcode] = useState(false);
useEffect(() => {
fetch(`/data/${product_id}`)
.then((res) => res.json())
.then((data) => {
setFiles(data);
setIsMapcode(data[0].code !== undefined);
});
}, [product_id]);
Therefore you should check its value inside a scope ({}):
<div className="col-3">
{isMapCode ? <Map files={files} /> : <div>No map</div>}
</div>
Notice that you don't need another state for it, you can check your files state:
const isMapCodeAvailable = data[0].code !== undefined;
<div className="col-3">
{isMapCodeAvailable ? <Map files={files} /> : <div>No map</div>}
</div>

Resources