ReactJs Hiding Some HTML depend on situation - javascript

I want to make the price tag also some other HTML contents hide/show depending on some data entry.
for example, if I get True it should be visible prices if it's gonna be False it must hide.
I'm sharing some code of my pages please give me ideas.
Thank you.
// react
import React from 'react';
// third-party
import classNames from 'classnames';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
// application
import AsyncAction from './AsyncAction';
import Points from './Points';
import { cartAddItem } from '../../store/cart';
import { Quickview16Svg } from '../../svg';
import { quickviewOpen } from '../../store/quickview';
import { url } from '../../services/utils';
function ProductCard(props) {
const {
product,
layout,
quickviewOpen,
cartAddItem,
} = props;
const containerClasses = classNames('product-card', {
'product-card--layout--grid product-card--size--sm': layout === 'grid-sm',
'product-card--layout--grid product-card--size--nl': layout === 'grid-nl',
'product-card--layout--grid product-card--size--lg': layout === 'grid-lg',
'product-card--layout--list': layout === 'list',
'product-card--layout--horizontal': layout === 'horizontal',
});
let badges = [];
let image;
let price;
let features;
if (product.badges.includes('sale')) {
badges.push(<div key="sale" className="product-card__badge product-card__badge--sale">Sale</div>);
}
if (product.badges.includes('hot')) {
badges.push(<div key="hot" className="product-card__badge product-card__badge--hot">Hot</div>);
}
if (product.badges.includes('new')) {
badges.push(<div key="new" className="product-card__badge product-card__badge--new">New</div>);
}
badges = badges.length ? <div className="product-card__badges-list">{badges}</div> : null;
if (product.images && product.images.length > 0) {
image = (
<div className="product-card__image product-image">
<Link to={url.product(product)} className="product-image__body">
<img className="product-image__img" src={product.images[0]} alt="" />
</Link>
</div>
);
}
if (product.discountPrice) {
price = (
<div className="product-card__prices">
<span className="product-card__new-price"><Points value={product.price} /></span>
{' '}
<span className="product-card__old-price"><Points value={product.discountPrice} /></span>
</div>
);
} else {
price = (
<div className="product-card__prices">
<Points value={product.price} />
</div>
);
}
if (product.attributes && product.attributes.length) {
features = (
<ul className="product-card__features-list">
{product.attributes.filter((x) => x.featured).map((attribute, index) => (
<li key={index}>{`${attribute.name}: ${attribute.values.map((x) => x.name).join(', ')}`}</li>
))}
</ul>
);
}
return (
<div className={containerClasses}>
<AsyncAction
action={() => quickviewOpen(product.slug)}
render={({ run, loading }) => (
<button
type="button"
onClick={run}
className={classNames('product-card__quickview', {
'product-card__quickview--preload': loading,
})}
>
<Quickview16Svg />
</button>
)}
/>
{badges}
{image}
<div className="product-card__info">
<div className="product-card__name">
<Link to={url.product(product)}>{product.name}</Link>
<br />
<br />
</div>
{features}
</div>
<div className="product-card__actions">
<div className="product-card__availability">
Availability:
<span className="text-success">In Stock</span>
</div>
{price}
<div className="product-card__buttons">
<AsyncAction
action={() => cartAddItem(product)}
render={({ run, loading }) => (
<React.Fragment>
<button
type="button"
onClick={run}
className={classNames('btn btn-primary product-card__addtocart', {
'btn-loading': loading,
})}
>
Add To Cart
</button>
<button
type="button"
onClick={run}
className={classNames('btn btn-secondary product-card__addtocart product-card__addtocart--list', {
'btn-loading': loading,
})}
>
Add To Cart
</button>
</React.Fragment>
)}
/>
</div>
</div>
</div>
);
}
ProductCard.propTypes = {
/**
* product object
*/
product: PropTypes.object.isRequired,
/**
* product card layout
* one of ['grid-sm', 'grid-nl', 'grid-lg', 'list', 'horizontal']
*/
layout: PropTypes.oneOf(['grid-sm', 'grid-nl', 'grid-lg', 'list', 'horizontal']),
};
const mapStateToProps = () => ({});
const mapDispatchToProps = {
cartAddItem,
quickviewOpen,
};
export default connect(
mapStateToProps,
mapDispatchToProps,
)(ProductCard);
Here I want to hide prices in some onload situations. This is my homepage Carousel.

You can use code like this. It will only render the component if the boolean evaluates to a truthy value.
const { isVisible } = this.props; // Or wherever you want to get your boolean from
return (
<div>
{isVisible && <MyComponent />}
</div>

You refer to Conditional rendering, there are a couple ways to do that:
<div>
{someCondition && <p>The condition is true</p>}
</div>
Or if you want a if else rendering:
<div>
{someCondition ? <p>The condition is true</p> : <p>The condition is false</p>}
</div>
You can find more info in react docs

Related

React: implementing a router

I tried implementing browser router, but to no success. i'm having trouble with useParams hook, and just the router in general. Looked through multiple posts and i just wasn't able to get it working. I'll post the most barebones code below, hoping someone knows the solution. I removed the traces of the router, since it didn't work.
App.js is currently empty:
const App=()=> {
return (
<Main/>
);
}
Main.jsx is my main element, where components change. There isn't a page change per se, everything is in the main element. values get passed through props into main and written into state, so the useEffect can change visibility of components based on what you chose, first category, then recipe.:
const Main =()=> {
const [showElement, setShowElement] = useState("category");
const [selectedCategory, setSelectedCategory] = useState();
const [selectedRecipe, setSelectedRecipe] = useState();
useEffect(()=> {
if (selectedRecipe) {
setShowElement("recipe")
} else if (selectedCategory) {
setShowElement("recipeSelection")
}
window.scrollTo(0, 0)
}, [selectedCategory][selectedRecipe]);
return (
<>
<Header />
<main className="main">
<div>
<div>
{showElement === "category" &&
<CategoryWindow
passSelectedCategory={setSelectedCategory}
/>
}
</div>
<div>
{showElement === "recipeSelection" &&
<RecipeSelection
value={selectedCategory}
passSelectedRecipe={setSelectedRecipe}
/>
}
</div>
<div>
{showElement === "recipe" &&
<RecipeWindow
value={selectedRecipe}
/>
}
</div>
</div>
</main>
</>
)
}
This is the recipe picker component. For example when i click on curry, i'd like the url to show /food/curry. None od the names are hardcoded, everything comes from a javascript object:
const RecipeSelection =(props)=> {
const recipies = Recipies.filter(x=>x.type === props.value);
return (
<div className="selection-div">
<div className="selection-inner">
{recipies.map(selection =>
<>
<img src={require(`../images/${selection.id}.png`)}
className="selection-single"
key={selection.id}
alt={"picture of " + selection.id}
onClick={()=> props.passSelectedRecipe(selection.id)}
>
</img>
<div className="container-h3"
onClick={()=> props.passSelectedRecipe(selection.id)}
>
<h3 className="selection-h3">{selection.name}</h3>
</div>
</>
)}
</div>
</div>
)
}

pass some value back to parent component in next js

In my nextjs project I'm displaying posts from different tags and each post have many tags. I have a post_by_tags component and I'm using that component in different sections on home page to display posts from different tags. I don't want to show repeating content as some posts have same tags and I have a array to keep post ids that are visible to website. Now I want a way to keep post ids from child component to send back to parent component which updates the array so I can filter out these posts from post object. I find some examples but mostly these are tied with onclick or onchange something like that.
Here is my parent component code:
import Head from 'next/head'
import Image from 'next/image'
import Layout from '../components/Layout';
import Hero from '../components/Hero';
import Developed_country from '../components/Developed_country';
import Posts_by_tags from '../components/Post_by_tags';
import Attorneys from '../components/Attorneys';
import Business_formation from '../components/Business_formation';
import Case from '../components/Case';
export async function getServerSideProps(context) {
// Fetch data from external API
const res = await fetch(`https://dashboard.toppstation.com/api/blogs`);
const data = await res.json();
// Pass data to the page via props
return {
props: { blogs:data}
}
}
export default function Home({blogs}) {
const blog_post_id = [];
const pull_data = (data) => {
console.log(data); // LOGS DATA FROM CHILD)
}
return (
<Layout>
<Hero/>
<Developed_country/>
<Posts_by_tags tag='business' bg='bg_grey' posts={blogs} func={pull_data}/>
<Business_formation/>
<Attorneys/>
<Posts_by_tags tag='png' bg='bg_white' posts={blogs} />
<Posts_by_tags tag='image' bg='bg_grey' posts={blogs} />
<Posts_by_tags tag='png' bg='bg_white' posts={blogs} />
<Case/>
</Layout>
)
}
Child component:
import Blogimg from '../public/img/blog.png';
import btn_arrow from '../public/img/btn_arrow.svg';
import styles from '../styles/Home.module.css';
export default function Posts_by_tags(props){
props.func('My name is xyz');
const bg = props.bg;
let align = ['start','center','end'];
let post_tags = [];
const postIds= [];
const blog_posts = props.posts.filter(bpost=>{
bpost.tags.forEach(tag => {
if(tag.toLowerCase() === props.tag){
return postIds.push(bpost._id);
}
})
});
const posts = props.posts.filter(p => {
if( (postIds.indexOf(p._id) !== -1) && p.visibility==true){
return p;
}
}).slice(0,3);
return(
<>
{posts.length == 0 ? null :(
<section id={styles.postsbytags} className={bg}>
<div className='wrapper'>
<div className="container section posts_by_tags section_ptb">
<div className='row'>
<div className='col-sm-12'>
<h3 className={`${styles.heading3} text-center`}><span className={`${styles.heading3span} ${bg}`}>{props.tag}</span></h3>
</div>
</div>
<div className='row pt_100'>
{posts.map( (post, index) =>(
<div id={`post-${post._id}`} className={`col-md-4 d-flex justify-content-md-${align[index]} justify-content-center`} key={post._id}>
<div className={styles.blog_post}>
<div className={`${styles.blog_image} text-center`}>
<span className={styles.blog_tag}>{props.tag}</span>
<Image className="img-fluid" src={post.image} alt={post.title} width={450} height={400} layout='responsive'/>
</div>
<div className='blog_content'>
<h4 className={styles.blog_title}>{post.title}</h4>
<p className={styles.blog_desc}>{post.description.split(' ').slice(0, 10).join(' ')}...</p>
</div>
</div>
</div>
))}
</div>
<div className='row'>
<div className='col-sm-12'>
<div className='blog_category pt_50'>
<a href="" className={ `btn ${styles.btn_tags} `}>See More {props.tag} <i className={styles.btn_icon}><Image src={btn_arrow} alt="btn-icon"/></i></a>
</div>
</div>
</div>
</div>
</div>
</section>
)}
</>
);
}```

React TypeError: setAvailability is not a function

I made a Christmas gifts list with React and I would like to change the available prop from true to false when a user clicks on "I want to offer this gift" but there is an error and I don't know why. The error is : TypeError: setAvailability is not a function
Here is my Book component:
function Book({available, setAvailability}) {
return (
<div className="gift-item-availability">
{ available ? <p className="gift-item-avail">Available</p> : <p className="gift-item-unavail">Booked</p> }
{ available ? <p className="gift-item-action" onClick={()=> setAvailability(false)}>I want to offer this gift</p> : null }
</div>
)
}
export default Book
Here is my Gift Component :
import {React, useState} from "react"
import '../styles/GiftItem.css'
import CurrencyFormat from 'react-currency-format';
import Book from "./Book";
function GiftItem({image, name, available, lien1, lien2, lien3, price, category}) {
const setAvailability = useState({available})
return (
<li className='gift-item'>
<CurrencyFormat value={price} displayType={'text'} thousandSeparator={true} suffix={'€'} renderText={value => <div className="gift-item-price">{value}</div>} />
<div className="gift-item-cover">
<img className="gift-item-cover" src={ window.location.origin + "/img/"+ image } alt={ name } />
</div>
<h2 className="gift-item-name">{ name }</h2>
<div className="gift-item-details">
<Book available={available} setAvailability={setAvailability} />
<div className="gift-item-link">
{ lien3 ? <img src={ window.location.origin + "/img/amazon.png"} alt="Amazon" /> : null }
{ lien1 ? <img src={ window.location.origin + "/img/picwictoys.png"} alt="Pic Wic Toys" /> : null }
{ lien2 ? <img src={ window.location.origin + "/img/king_jouet.png"} alt="King Jouet" /> : null }
</div>
</div>
</li>
)
}
export default GiftItem
And the complete List Component :
import {React, useState} from "react"
import { giftList } from '../data/giftList'
import '../styles/ShoppingList.css'
import GiftItem from './GiftItem'
import Categories from "./Categories"
function ShoppingList() {
const [activeCategory, setActiveCategory] = useState('')
const categories = giftList.reduce(
(acc, gift) =>
acc.includes(gift.category) ? acc : acc.concat(gift.category),
[]
)
return (
<div className='shopping-list'>
<Categories
categories={categories}
setActiveCategory={setActiveCategory}
activeCategory={activeCategory}
/>
<ul className='gift-list'>
{giftList.map(({image, name, available, lien1, lien2, lien3, price, category}) => (
!activeCategory || activeCategory === category ? (
<GiftItem
image={image}
name={name}
available={available}
lien1={lien1}
lien2={lien2}
lien3={lien3}
price={price}
key={name}
/>
) : null
))}
</ul>
</div>
)
}
export default ShoppingList
Thanks a lot for your help !!!
The useState hook returns an array containing two elements, not a function. The first item in the array is the value, the second item is the function used to update that value. Typically you'd destructure it like this:
const [availability, setAvailability] = useState({available})
The useState documentation has some more helpful information.
It should be const [availability, setAvailability] = useState(true);
useState return an array not the function.
you can then use setAvailability(false) to set availability state as false.

How to refactor react component separate for rendering and logic?

I have react component:
function FavoritesListItem({ merchant, config, isFavorited }) {
const {
name, id, logoUrls = {}, offersCount, rebate, showRebate,
} = merchant;
const { rebateOptions } = config;
return (
const renderActiveMerchant = () => (
<div
className="mn_favoriteMerchant"
data-merchant-id={id}
data-merchant-name={name}
role="listitem"
data-test="favorite-merchant"
>
<div className="mn_favoriteMerchantInner">
<MerchantExperienceLink
className="mn_favoriteMerchantLink"
merchant={merchant}
title={`Opens merchant detail page at ${name}`}
>
<FavoriteIcon
merchantId={id}
merchantName={name}
labelUnfavorite={`Remove ${name} from Favorites list`}
showSpinner={!isFavorited}
/>
<div className="mn_logo"><img data-test="favorited-merchant-logo" src={logoUrls._120x60} alt={name} /></div>
<p className="mn_offersCount" data-test="favorited-merchant-offers-count">{offersCount} offers available </p>
</MerchantExperienceLink>
{rebate && (
<MerchantClickUrlLink className="mn_favoriteMerchantRebateLink" merchant={merchant}>
<div className="mn_rebate">
{showRebate
? <MerchantRebate {...rebate} {...rebateOptions} />
: <MerchantNoRebateLabel />}
? <MerchantRebate {...rebate} {...rebateOptions} />
: <MerchantNoRebateLabel />}
</div>
</MerchantClickUrlLink>
)}
</div>
</div>
);
const renderDeactivatedMerchant = () => (
<div
className="mn_favoriteMerchant"
data-merchant-id={id}
data-merchant-name={name}
role="listitem"
data-test="favorite-merchant"
>
<div className="mn_favoriteMerchantInner">
<MerchantExperienceLink
className="mn_favoriteMerchantLink"
merchant={merchant}
title={`Opens merchant detail page at ${name}`}
>
<FavoriteIcon
merchantId={id}
merchantName={name}
labelUnfavorite={`Remove ${name} from Favorites list`}
showSpinner={!isFavorited}
/>
<div className="mn_logo mn_noRebateMerchantLogo">
<img data-test="favorited-merchant-logo" src={logoUrls._120x60} alt={name} />
</div>
{rebate && (
<div className="mn_rebate mn_deactivatedRebate">
{
showRebate
? <MerchantNoRebateLabel />
: <MerchantRebate {...rebate} />
}
</div>
)}
</MerchantExperienceLink>
</div>
</div>
);
return (
merchant.type === 'Deactivated Merchant' ? renderDeactivatedMerchant() : renderActiveMerchant()
);
}
const mapStateToProps = () => {
const selectFavoriteByMerchantId = makeSelectFavoriteByMerchantId();
return (state, { merchant }) => ({
isFavorited: selectFavoriteByMerchantId(state, merchant.id),
});
};
export default connect(mapStateToProps)(FavoritesListItem);
and need to refactor it to 2 separate components which will be just render renderDeactivatedMerchant and renderActiveMerchant. All other logic should be in this component FavoritesListItem
So I created components this way:
export class FavoritesListItemDeactivatedMerchant extends Component ({ merchant, config, isFavorited }) {
render() {
const { merchant, config, isFavorited } = this.props;
const {
name, id, logoUrls = {}, rebate, showRebate,
} = merchant;
const { rebateOptions } = config;
return (
<div
className="mn_favoriteMerchant"
data-merchant-id={id}
data-merchant-name={name}
role="listitem"
data-test="favorite-merchant"
>
<div className="mn_favoriteMerchantInner">
<MerchantExperienceLink
className="mn_favoriteMerchantLink"
merchant={merchant}
title={`Opens merchant detail page at ${name}`}
>
<FavoriteIcon
merchantId={id}
merchantName={name}
labelUnfavorite={`Remove ${name} from Favorites list`}
showSpinner={!isFavorited}
/>
<div className="mn_logo mn_noRebateMerchantLogo">
<img data-test="favorited-merchant-logo" src={logoUrls._120x60} alt={name} />
</div>
{rebate && (
<div className="mn_rebate mn_deactivatedRebate">
{
showRebate
? <MerchantNoRebateLabel />
: <MerchantRebate {...rebate} />
}
</div>
)}
</MerchantExperienceLink>
</div>
</div>
);
}
}
const mapStateToProps = () => {
const selectFavoriteByMerchantId = makeSelectFavoriteByMerchantId();
return (state, { merchant }) => ({
isFavorited: selectFavoriteByMerchantId(state, merchant.id),
});
};
export default connect(mapStateToProps)(FavoritesListItemDeactivatedMerchant);
Project builded without errors and also no errors in console. But it's not render this component in browser. What I'm doing wrong? Please, help.
You have confused the syntax for function and class components and created a weird mash-up that combines both:
export class FavoritesListItemDeactivatedMerchant extends Component ({ merchant, config, isFavorited }) {
Those props make no sense in a class! I think you meant to write this:
export const FavoritesListItemDeactivatedMerchant = ({ merchant, config, isFavorited }) => {
or
export function FavoritesListItemDeactivatedMerchant({ merchant, config, isFavorited }) {
Personally I think you can improve this code by having a shared RenderMerchant with a prop isDeactivated instead of having separate components for active and deactivated. There is a lot of repeated code between the two cases which you want to avoid.

How to remove a button if there is no more info in the api

The following code is running smoothly, but I want to implement it in a way that when I do a getNextPers() and there is no info, it hides/removes the Ver Mais button. I've been looking for solutions but have found none, so any help is good. Thank you.
import React from 'react';
import ReactDOM from 'react-dom';
import axios from 'axios';
class List extends React.Component {
constructor(props){
super(props);
this.state = {
personagens: [],
page: 1,
showBtn: true,
};
this.getNextPers = this.getNextPers.bind(this);
}
getNextPers(){
const peopleApiEndpoint = `https://swapi.co/api/people/${this.state.page}`;
axios.get(peopleApiEndpoint).then((p) =>
if(p=={}){
this.setState({ showBtn: false });
}
else {
this.setState({ personagens: this.state.personagens.concat(p), page: this.state.page+1 })
}
);
}
render(){
return (
<div>
<p><b>Personagens:</b></p>
{this.state.personagens.map((pers, i) => (
<div key={i}>
<br />
<p><i>Name:</i> {pers.data.name}</p>
<p><i>Height:</i> {pers.data.height} cm</p>
<p><i>Mass:</i> {pers.data.mass} kg</p>
</div>
))}
<button onClick={this.getNextPers}>Ver Mais</button>
</div>
);
}
}
ReactDOM.render(<List />, document.getElementById('root'));
The real problem is here:
axios.get(peopleApiEndpoint).then((p) => {
if (p == {}) { // THIS WILL NEWER WORK AS EXPECTED
this.setState({showBtn: false});
} else {
this.setState({
personagens: this.state.personagens.concat(p),
page: this.state.page + 1
});
}
});
Also swapi return 404 when there is no more results instead of empty object so you need to add catch block to your axios.get as described in docs: https://github.com/axios/axios#handling-errors
axios.get(peopleApiEndpoint).then((p) => {
this.setState({
personagens: this.state.personagens.concat(p),
page: this.state.page + 1
});
}).catch((err) => {
this.setState({showBtn: false});
});
Now you can use conditional rendering like:
{(this.state.showBtn && <button onClick={this.getNextPers}>Ver Mais</button>)}
First thing getNextPers does not return anything and you can achieve the show/hide by using condintion in your code
{ this.your_condition ?
<button onClick={this.getNextPers}>Ver Mais</button> : ''
}
As addition to Ramya answer you can also use
render(){
return (
<div>
<p><b>Personagens:</b></p>
{this.state.personagens.map((pers, i) => (
<div key={i}>
<br />
<p><i>Name:</i> {pers.data.name}</p>
<p><i>Height:</i> {pers.data.height} cm</p>
<p><i>Mass:</i> {pers.data.mass} kg</p>
</div>
))}
{ this.state.showBtn && <button onClick={this.getNextPers}>Ver Mais</button> }
</div>
);
}
Since you're storing the showBtn state in your component, you can use it to conditionally render the button as follows:
render(){
return (
<div>
<p><b>Personagens:</b></p>
{this.state.personagens.map((pers, i) => (
<div key={i}>
<br />
<p><i>Name:</i> {pers.data.name}</p>
<p><i>Height:</i> {pers.data.height} cm</p>
<p><i>Mass:</i> {pers.data.mass} kg</p>
</div>
))}
{ (this.state.showBtn) ?
<button onClick={this.getNextPers}>Ver Mais</button>
:
null
}
</div>
);
}

Categories

Resources