Search not found message is displaying while loading the spinner - reactjs

If my search is not returning any results, then I will display a message Does not match any results! in Home.js screen. I would like to make the display of message more efficiently. I have a loading spinner running while loading the home screen, you could see that text is also displaying along while running the spinner ( attached screen shot)
I would like to display that message only if the search is not returning any results/ searched data. In all other cases, it should be hidden ...How can I put that condition ?
const [playerList, setPlayerList] = useState([]);
const [searchTerm, setSearchTerm] = useState("");
const handleChange = event => {
setSearchTerm(event.target.value);
};
useEffect(() => {
const results = playerList.filter(player =>
player.name.toLowerCase().includes(searchTerm) || player.name.toUpperCase().includes(searchTerm) || player.position.toLowerCase().includes(searchTerm)
|| player.position.toUpperCase().includes(searchTerm)
);
setSearchResults(results);
}, [searchTerm, playerList]);
return (
<div className="App">
<div className="wrapper">
<div className="playerList_header">
<h1>Players</h1>
<label>
<div className="playerSearch_Home">
<div className="playerSearch_Icon">
<img alt="" src="/images/search-image-player.jpg"></img>
</div>
<input type="text" className="playerSearch_Home_Input" placeholder="Search players..." value={searchTerm} onChange={handleChange} />
</div>
</label>
</div>
<div>
{!searchResults.length && (<div> <p className="noSearchData"> Does not match any results! </p> </div>)}
<div className="playerList_home_page">
{isLoading ? (
<div className="loader">
<div className="bubble"></div>
<div className="bubble"></div>
<div className="bubble"></div>
<div className="bubble"></div>
</div>
) : (
<div className="grid-container">
{
searchResults.map(({ id, image, position, phonenumber, name }) => (
<div key={id} className="grid-item">
{
deleteIcon.show && (
<span className="deletePlayerButton" onClick={deletePlayer(id)}>
<img className="deletePlayerimg" src="/images/delete.png"></img>
</span>
)}
<div>
<img alt="" className="playerProfilePic_home_tile" key={image} src={image}></img>
</div>
<div className="playerProfile_grid_border">
<span className="rec_name_position_data">
<h3 key={name}>{name}</h3>
<span className="playerPosition_home_tile" key={position}>{position}</span>
</span>
</div>
<span className="phoneNumber_home">
<img src="/images/phone.png" alt={"phoneTooltip.show"} key={id} name="phoneNumberhomeicon" onClick={displayPhoneToolTip(id)} />
</span>
{phoneTooltip === id && (
<div className="tooltip_PhoneNumber_home" key={phonenumber}>{phonenumber}</div>
)}
</div>
))
}
</div>
)}
</div>
</div>
</div>
<AlertDialog
onDelete={onDelete}
open={deleteDialog}
onClose={() => setDeleteDialog(false)}
playerId={playerId}
/>
</div>
);

Add another condition with isLoading like so
{!searchResults.length && !isLoading && (<div> <p className="noSearchData"> Does not match any results! </p> </div>)}

Related

react map through product info and capture individual Input state as value

I am trying to pull data and map through. I am stuck at quantity bit where my state updates all quantity input values instead just the one that I am trying to increase.
How can modify this so that the when I map trough only quantity field that I change would set to that state so I can use it later to add to basket.
<div>
{receivedProductsKitchen ? receivedProductsKitchen.map( products => {
return(
<div className="main-product-container" key={products.product_id}>
<div className="product-block-container">
<div className="product-name">
<span>{products.product_name}</span>
</div>
<div className="product-image-box">
<img src={products.product_image_url} alt={products.product_name}/>
</div>
<div className="product-information">
<span className="product-information-drop-down">Product Information D</span>
</div>
<div className="product-description">
<span className="product-description-text">{products.product_description}</span>
</div>
<div className="quantity-input-box">
<input id={products.product_id} type="number" placeholder="1" onChange={(e) => handleQuantity(e.target.value)}/>
</div>
</div>
</div>
);
})
: ''}
</div>
Found my problem by not mapping id for the given quantity input.
My solution:
const handleQuantity = (e, id) =>{
e.preventDefault();
setQuantity({id : id, value: e.target.value});
}
console.log(quantity)
const DisplayKitchen = () => {
return(
<div className="accessories-main-top-container-actions">
<div className="accessories-main-container-all-products">
{receivedProductsKitchen ? receivedProductsKitchen.map( products => {
return(
<div key={products.product_id}>
<div className="main-product-container" >
<div className="product-block-container" >
<div className="product-name">
<span className="product-text">{products.product_name}</span>
</div>
<div className="product-image-box">
<img className="product-img" src={products.product_image_url} alt={products.product_name}/>
</div>
<div className="product-information">
<span className="product-information-drop-down">Product Information D</span> <span className="arrow-down">{ArrowDownwardIcon}</span>
</div>
<div className="product-description">
<span className="product-description-text">{products.product_description}</span>
</div>
<div className="quantity-input-box">
<input type="number" value={quantity.id === products.product_id ? quantity.value : 1 } placeholder="1" onChange={(e) => handleQuantity(e,products.product_id)}/>
</div>
<div className="add-to-basket-container">
<AddToBasket />
</div>
</div>
</div>
</div>
);
})
: ''}
</div>
</div>
);
Hope it helps some one if any one got stuck :)

Cannot flush updates when React is already rendering - Sweet

I get the following error when rendering a SweetAlert.. not sure how to solve?
index.js:1451 Warning: unstable_flushDiscreteUpdates: Cannot flush updates when React is already rendering.
in n (at LoginOverlay/index.js:248)
in div (at LoginOverlay/index.js:82)
in Formik (at LoginOverlay/index.js:66)
in LoginOverlay (created by ConnectFunction)
in ConnectFunction (created by Context.Consumer)
in Route (at Routes.js:270)
in div (created by ForwardRef(MotionComponent))
in ForwardRef(MotionComponent) (at Routes.js:263)
in Switch (at Routes.js:262)
in PresentationLayout (at Routes.js:261)
in Route (at Routes.js:260)
in Switch (at Routes.js:258)
in Suspense (at Routes.js:257)
in PresenceChild (created by AnimatePresence)
Code:
const LoginOverlay = (props) => {
const history = useHistory();
const { magic, login, clearError } = props;
// useEffect(() => {
// if (magic.entity?.loggedIn && localStorage.getItem('did_token')) {
// //history.push('/business/home');
// }
// }, [magic.loading, magic.showInfoDialog]);
return (
<Formik
initialValues={{
email: ''
}}
validationSchema={yup.object().shape({
email: yup
.string()
.email('Must be valid email address')
.min(3)
.required('Email is required')
})}
onSubmit={async (values, actions) => {
console.log(values, props);
props.login(values.email);
}}>
{(props) => (
<div className="app-wrapper min-vh-100 bg-white">
<div className="hero-wrapper w-100 bg-composed-wrapper bg-midnight-bloom min-vh-100">
<div className="flex-grow-1 w-100 d-flex align-items-center">
<div
className="bg-composed-wrapper--image opacity-2"
style={{ backgroundImage: 'url(' + hero6 + ')' }}
/>
<div className="bg-composed-wrapper--bg bg-second opacity-7" />
<div className="bg-composed-wrapper--content p-3 p-md-5">
<Container>
<Card className="rounded-sm modal-content p-3 bg-white-10">
<Card className="rounded-sm overflow-hidden shadow-xxl font-size-sm p-3 p-sm-0">
<Row className="no-gutters">
<Col
lg="6"
className="d-flex align-items-center justify-content-center flex-column">
<Form onSubmit={props.handleSubmit}>
<div className="divider-v divider-v-lg d-none d-lg-block" />
<div className="text-center mt-4">
<h1 className="font-size-xxl mb-1 font-weight-bold">
Login
</h1>
<br />
<p className="mb-0 text-black-50">
Enter you email below to sign up or sign in to
your account
</p>
<br />
<div className="mb-0 text-black-50">
<div className="form-group mb-6">
<Input
type="text"
{...props.getFieldProps('email')}
placeholder="Email"
invalid={
props.errors.email && props.touched.email
}
valid={
!props.errors.email && props.touched.email
}
/>
<FormFeedback>
{props.errors.email}
</FormFeedback>
</div>
<div className="text-center py-4">
<Button
type="submit"
disabled={
magic.loading || props.isSubmitting
}
className="font-weight-bold w-50 my-2"
color="second">
Submit
</Button>
{/* <LaddaButton
type="submit"
className="m-2 btn btn-second"
loading={(magic.loading || props.isSubmitting)}
onClick={(e) => {
e.preventDefault();
props.submitForm();
}}
data-style={EXPAND_LEFT}>
Submit
</LaddaButton> */}
</div>
</div>
</div>
</Form>
</Col>
<Col
lg="6"
className="d-flex align-items-center justify-content-center flex-column bg-secondary">
<div className="p-3">
<div className="p-4">
<div className="d-block d-xl-flex">
<div className="mt-0 mt-xl-1 mb-md-2 mb-lg-0">
<FontAwesomeIcon
icon={['far', 'heart']}
className="font-size-xl text-first"
/>
</div>
<div className="pl-0 pl-xl-3">
<div className="text-black font-weight-bold font-size-lg mb-1">
Have we anything for here?
</div>
<p className="mb-0 text-black-50">
Have we anything for here?
</p>
</div>
</div>
</div>
<div className="p-4">
<div className="d-block d-xl-flex">
<div className="mt-0 mt-xl-1 mb-md-2 mb-lg-0">
<FontAwesomeIcon
icon={['far', 'lightbulb']}
className="font-size-xl text-first"
/>
</div>
<div className="pl-0 pl-xl-3">
<div className="text-black font-weight-bold font-size-lg mb-1">
Have we anything for here?
</div>
<p className="mb-0 text-black-50">
Have we anything for here?
</p>
</div>
</div>
</div>
<div className="p-4">
<div className="d-block d-xl-flex">
<div className="mt-0 mt-xl-1 mb-md-2 mb-lg-0">
<FontAwesomeIcon
icon={['far', 'user']}
className="font-size-xl text-first"
/>
</div>
<div className="pl-0 pl-xl-3">
<div className="text-black font-weight-bold font-size-lg mb-1">
Have we anything for here?
</div>
<p className="mb-0 text-black-50">
Have we anything for here?
</p>
</div>
</div>
</div>
</div>
</Col>
</Row>
</Card>
</Card>
</Container>
</div>
</div>
<div className="hero-footer w-100 pb-4">
<Container>
<div className="py-3 d-block d-lg-flex font-size-xs justify-content-between">
<div className="text-center d-block mb-3 mb-md-0 text-white">
XXXXX 2021
</div>
<Nav className="nav-transparent justify-content-center">
<NavItem>
<NavLinkStrap
className="text-white-50"
href="#/"
onClick={(e) => e.preventDefault()}>
Privacy Policy
</NavLinkStrap>
</NavItem>
<NavItem>
<NavLinkStrap
className="text-white-50"
href="#/"
onClick={(e) => e.preventDefault()}>
Terms of Service
</NavLinkStrap>
</NavItem>
</Nav>
</div>
</Container>
</div>
</div>
<SweetAlert
title="Check your email"
show={!magic.entity?.loggedIn && magic.showInfoDialog}
html={`We emailed a magic link to ${props.values.email}</br>Click the link in your email and then return to this tab to log in or sign up.</br>`}
type="info"
showCancelButton={false}
showConfirmButton={false}
/>
<SweetAlert
title="Error"
show={!magic.entity?.loggedIn && magic.errorMessage}
html={magic.errorMessage}
type="error"
showCancelButton={false}
showConfirmButton={true}
onConfirm={() => clearError()}
/>
{
(localStorage.getItem("did_token") || magic.entity?.loggedIn ) && <Redirect to="/business/home" />
}
</div>
)}
</Formik>
Please check for any other alerts that is dependent. It happens when you are trying to access multiple alerts

Return a message for a search display zero search results in react hooks

If a search in React hooks has returned zero results, I would like to display a text message "No data available for the search criteria !" in the page ? I have tried a condition, but not sure where to add.
if(results.length == 0) {
return (
<div>No data available for the search criteria !</div>
)
}
const [searchTerm, setSearchTerm] = useState("");
const [searchResults, setSearchResults] = useState([]);
const handleChange = event => {
setSearchTerm(event.target.value);
};
useEffect(() => {
const results = playerList.filter(player =>
player.name.toLowerCase().includes(searchTerm) || player.name.toUpperCase().includes(searchTerm) || player.position.toLowerCase().includes(searchTerm)
|| player.position.toUpperCase().includes(searchTerm)
);
setSearchResults(results);
}, [searchTerm]);
//
return (
<div className="App">
<label>
<div className="playerSearch_Home">
<div className="playerSearch_Icon">
<img src="/images/search-image-player.jpg"></img>
</div>
<input type="text" className="playerSearch_Home_Input" placeholder="Search players..." value={searchTerm} onChange={handleChange} />
</div>
</label>
<div className="playerList_home_page">
<div className="grid-container">
{
searchResults.map(player => {
return (
<div className="grid-item">
<div>
<img className="playerProfilePic_home_tile" key={player.image} src={player.image}></img>
</div>
<div className="playerProfile_grid_border">
<h3 key={player.name}>{player.name}</h3>
<span className="playerPosition_home_tile" key={player.position}>{player.position}</span>
</div>
</div>
);
})
}
</div>
</div>
</div>
);
You use simply ternary operator, something like this :
{
searchResults.length ?
searchResults.map(player => {
return (
<div className="grid-item">
<div>
<img className="playerProfilePic_home_tile" key={player.image} src={player.image}></img>
</div>
<div className="playerProfile_grid_border">
<h3 key={player.name}>{player.name}</h3>
<span className="playerPosition_home_tile" key={player.position}>{player.position}</span>
</div>
</div>
);
}) :
"No data available for the search criteria !"
}
You can use ternary operator based on the length of searchResults.
Please check the code below:
return (
<div className="App">
<label>
<div className="playerSearch_Home">
<div className="playerSearch_Icon">
<img src="/images/search-image-player.jpg"></img>
</div>
<input type="text" className="playerSearch_Home_Input" placeholder="Search players..." value={searchTerm} onChange={handleChange} />
</div>
</label>
<div className="playerList_home_page">
<div className="grid-container">
{
**searchResults.length > 0 ?**
searchResults.map(player => {
return (
<div className="grid-item">
<div>
<img className="playerProfilePic_home_tile" key={player.image} src={player.image}></img>
</div>
<div className="playerProfile_grid_border">
<h3 key={player.name}>{player.name}</h3>
<span className="playerPosition_home_tile" key={player.position}>{player.position}</span>
</div>
</div>
);
})
**} : <p>Zero records found for the Search</p>**
</div>
</div>
</div>
);
You need to make a conditional render based on the length of the search results array. If there's nothing in the array, then it will show a message.
{!searchResults.length && (<div> <p> No data available for the search criteria ! </p> </div>) }
return (
<div className="App">
<label>
<div className="playerSearch_Home">
<div className="playerSearch_Icon">
<img src="/images/search-image-player.jpg"></img>
</div>
<input type="text" className="playerSearch_Home_Input" placeholder="Search players..." value={searchTerm} onChange={handleChange} />
</div>
</label>
{!searchResults.length && (<div> <p> No data available for the search criteria ! </p> </div>) }
<div className="playerList_home_page">
<div className="grid-container">
{
searchResults.map(player => {
return (
<div className="grid-item">
<div>
<img className="playerProfilePic_home_tile" key={player.image} src={player.image}></img>
</div>
<div className="playerProfile_grid_border">
<h3 key={player.name}>{player.name}</h3>
<span className="playerPosition_home_tile" key={player.position}>{player.position}</span>
</div>
</div>
);
})
}
</div>
</div>
</div>
);

How to not repeat the same code and use components or functions in react instead?

i have a component within which i want to display the card that accepts the list and another card next to it that displays ImageComponent if state.complete. if not displays the status text.
As you see from code below,
render() {
return (
<OuterComponent>
<div className="wrapper">
<div className="card">
<form onSubmit={this.on_submit}>
<div className="top_content">
<div className="title">title</div>
</div>
<div className="content">
<label>
<div>
<SvgOne />
Plus button
</div>
<input
type="file"
onChange={this.handle_files}
multiple />
</label>
<ul className="files_list">
{this.state.files.map((f, index) => (
<li key={f.name}>
</li>
))}
</ul>
</div>
<div className="bottom_content">
<button type="submit">
Submit
</button>
</div>
</form>
</div>
{(this.state.loading || this.props.list_id) &&
<div>
{this.state.complete
? <Fragment>
<div className="content">
<ChildComponentOne/>
</div>
<div className="bottom_content">
<div className="title">title</div>
</div>
</Fragment>
: <Fragment>
<div className="content">
{this.state.failed &&
<div>
<SvgRetry/>
</div>}
<div className="cancel_button">
<SvgClose/>
</div>
<div className={status_classes.join(' ')}>
{this.get_text}...
</div>
</div>
<div className="bottom_content">
{list && list.listname
? <div className="title">title</div>
: <div/>}
</div>
</Fragment>
}
</div>
</div>
</OuterComponent>
);
}
I have used the div with classname "content" repeatedly. It contains ImageComponent if the state.complete if not displays some other content with in. I have duplicated the code. But i wanted it to be a seperate component such that it could be used elsewhere.
What could be the best approach in this case. Could someone provide some insight into this. thanks.

JSX Bootstrap unterminated

I'm using bootstrap with react, and the compiler is failing on grounds that there is unterminated JSX contents. I've been through it a dozen times, and whichever way the ternary results, I don't see any unclosed tags. I'm new to react, so I suppose something else must be wrong. To cut down on code, I've only included the return():
<div className="container-fluid">
<div className="row">
<div className="col-12">
<SearchBar />
</div>
</div>
{this.state.results ? (
<div className="row">
<div className="col-12">
<div className="row">
<div className="col-6 offset-md-3">
<div className="row">
<div className="col">
<InputRange
maxValue={this.state.maxPrice}
minValue={this.state.minPrice}
value={this.state.priceRange}
formatLabel={x => {
return `£${x}`;
}}
onChange={value => this.setState({ priceRange: value })}
/>
</div>
</div>
<div className="row">
<div className="col">
Selection: {visibleResults.length}
</div>
</div>
<div>
</div>
<div className="row">
<div className="col-6 offset-md-3">
{visibleResults.map((item, index) => (
<Link to={`/listing/${item.id}`}>
<SearchResult result={item} key={index} />
</Link>
))}
</div>
</div>
</div>
</div>
) : (
<div className="row">
<div className="col">
<h1>LOADING...</h1>
</div>
</div>
)}
</div>
)
You need to close the div here:
<div className="row">
<div className="col">
Selection: {visibleResults.length}
</div>
</div>
<div> // This should be </div>
</div>

Resources