Why is my id failing in my React component? - reactjs

I need some help with this code it is giving an error of 'id' not defined, can have some assistance.
import React from "react";
const ContactCard = (props) => {
return(
<div className="item">
<div className="content">
<div className="Header">{props.contact.name}</div>
<div>{props.contact.email}</div>
</div>
<i className="trash alternate outline icon"
style={{color:"red", marginTop: "7px"}}
onClick = {() => props.clickHander(id)} >
</i>
</div>
);
}

As a guess, I believe instead of using id, use props.contact.id. That's why undefined error coming for id.

Going a little further than this answer, While you're bringing in props you can also destructure props, example:
import React from 'react'
const ContactCard = ({contact, clickHander}) => {
return (
<div className='item'>
<div className='content'>
<div className='Header'>{contact.name}</div>
<div>{contact.email}</div>
</div>
<i className='trash alternate outline icon' style={{ color: 'red', marginTop: '7px' }} onClick={() => clickHander(contact.id)}></i>
</div>
)
}
export default ContactCard

Related

I have to show stores listed on my platform depending upon the category selected which is shown on a sidebar

I have two api's one is to list categories and other is to list stores. Second api takes category id as input to show stores of that category, I am unable to list stores of specific category. Here's what I have written so far, I am able to hard code category id.
I want user to select category and then the output gives only those stores falling in that category. Can someone help me update this code?
import React, { useState, useEffect } from "react";
import logo from './logo.svg';
import './App.css';
import axios from "axios";
import appstore from './assets/astore.png'
import gplay from './assets/gplay.png'
import closeicon from './assets/closeicon.svg'
import videostore from './assets/videostore.svg'
import bigboxlogo from './assets/bigboxlogo.svg'
import createstore from './assets/createstore.svg'
import gettheapp from './assets/gettheapp.svg'
const App = () => {
const [category, setCategory] = useState([]);
const [store, setStore] = useState([]);
let attribute;
function showCat(catid) {
let attribute = catid.target.attributes.getNamedItem('data-cat').value;
console.log(attribute)
}
let catid = 10;
const fetchData = () => {
const categoryApi = "https://api.bigbox.online/api/v1/users/brand_categories?page=1&limit=10";
const storeApi = `https://api.bigbox.online/api/v1/users/brand_category_stores?brand_category_id=${catid}&page=1&limit=10`;
const getCategory = axios.get(categoryApi);
const getStore = axios.get(storeApi);
axios.all([getCategory, getStore]).then(
axios.spread((...allData) => {
const allCategory = allData[0].data.brand_categories;
const allStore = allData[1].data.stores;
// console.log(allCategory);
// console.log(allStore);
setCategory(allCategory);
setStore(allStore);
})
)
}
useEffect(() => {
fetchData()
}, [])
function removeDiv1() {
document.getElementById("ad1")
.outerHTML = "";
}
function removeDiv2() {
document.getElementById("ad2")
.outerHTML = "";
}
return (
<div className="App">
<div className="header">
<div className="header-left">
<img src={bigboxlogo} alt="" style={{ marginRight: "20px" }} />
<p>shop</p>
<p>what is bigbox?</p>
<p>bigbox app</p>
<p>for business</p>
<p>help</p>
</div>
<div className="header-right">
<img src={gettheapp} alt="" className="header-btn" />
<img src={createstore} alt="" className="header-btn" />
</div>
</div>
<div style={{ paddingLeft: "30px" }}>
<h1 style={{ fontSize: "80px", marginBottom: "5px" }}>video call your favourite brands.</h1>
<h5 style={{ fontSize: "28px", marginTop: "0", marginBottom: "15px", fontWeight: 400 }}>discover, follow and shop from your favourite stores. anytime. anywhere.</h5>
</div>
<div id="ad1" className="promo">
<p>get the shopping experience you deserve with our new and improved bigbox app</p>
<img src={appstore} alt="" className="promo-img" />
<img src={gplay} alt="" className="promo-img" />
<button className="button" onClick={removeDiv1}>
<img src={closeicon} alt="" style={{ cursor: "pointer" }} />
</button>
</div>
<div id="ad2" className="promo">
<p>selling online? setup your video store with bigbox and sell easily through video calls</p>
<img src={videostore} alt="" className="promo-img" />
<button className="button" onClick={removeDiv2}>
<img src={closeicon} alt="" style={{ cursor: "pointer" }} />
</button>
</div>
<div className="body">
<div className="sidebar">
<p style={{ fontSize: "20px", fontWeight: 600, marginTop: "0" }}>categories</p>
{
category.map((item) => (
<div onClick={showCat} data-cat={item.id} style={{ cursor: "pointer" }}>
{item.name}
</div>
))
}
</div>
<div className="centerbody">
<div>
<p className="numberStores">{store.length} stores</p>
</div>
<div className="home-body">
{
store.map((item) => (
<div key={item.id} className="home-store" >
<img src={item.brand_logo_url} alt="" className="brand-logo" />
<a style={{ textDecoration: 'none' }} href={`https://in.bigbox.online/${item.slug}`} target="_blank" >
<img className="home-storeImg" src={item.cover_pic_mobile_url} alt="" />
<h1>{item.brand.name}</h1>
</a>
</div>
))
}
</div>
</div>
</div>
</div>
);
}
export default App;
First of all, I think you should use the react's state, to handle data changes through selected items like you are trying to do. moreover, in showCat function, there is a problem, let's say you are getting the relevant data you need, but you are not using it or storing it for future use, so at the end of the function the data is not stored and you are losing it.
Therefore, you are not holding the selected id that you need for presenting the relevant stores.
Add new useState for holding the current selected catID like so: const [selectedCatID, setSelectedCatID] = useState();
function showCat(catid) {
setSelectedCatID(catid);
}
Then change the div attribute to pass the item.id through the onClick's function at triggering showCat.
3) <div onClick={() => showCat(item.id)} style={{ cursor: "pointer" }}>
Lastly modify the jsx to show the relevant stores by the current selected catid:
store.map((item) => {
if (selectedCatID && item.id === selectedCatID) {
return (
<div key={item.id} className="home-store" >
<img src={item.brand_logo_url} alt="" className="brand-logo" />
<a style={{ textDecoration: 'none' }} href={`https://in.bigbox.online/${item.slug}`} target="_blank" >
<img className="home-storeImg" src={item.cover_pic_mobile_url} alt="" />
<h1>{item.brand.name}</h1>
</a>
</div>
)}
return null; // for the case that does not match the id of the selected store.
)
Or either you can filter the stores before and just show to the screen the filtered stores by the selected catid.
let me know if you understood my explantaion. good luck!
EDIT:
when the catid will change the fetchData will run again, on every cat selected.
useEffect(() => {
fetchData()
}, [selectedCatID])
And also modify the storeApi for using the selectedCatID:
const storeApi = `https://api.bigbox.online/api/v1/users/brand_category_stores?brand_category_id=${selectedCatID}&page=1&limit=10`;

I keep getting `handleColor` is not a function error

I have some problem with a function I set up to change the background color of a button when it is clicked.
I setup the function in a parent component below:
import React, { useRef, useState } from 'react';
import Aside from './Aside';
import Content from './Content';
const Dashboard = () => {
let asideRef = useRef(null);
const handleColor = color => {
asideRef.current.style.backgroundColor = color;
};
return (
<div className="d-flex flex-row" id="main_wrapper">
<Aside handleColor={handleColor} postedRef={asideRef} />
<Content />
</div>
);
};
export default Dashboard;
in the child component it is called in this manner:
import { Link } from 'react-router-dom';
import React, { createRef } from 'react';
class Aside extends React.Component {
constructor(props) {
super(props);
this.state = {
btn: true,
btnEn: true,
background: '#fff',
};
this.handleClick = this.handleClick.bind(this);
}
handleClick = () => {
const { btn } = this.state;
this.setState({
btn: !btn,
});
};
render() {
const { btn, btnEn, background } = this.state;
const { handleColor, postedRef } = this.props;
console.log(this.props);
return (
<div className="d-flex flex-column asidebar" id="aside_wrapper" style={{ width: '20%', height: '100vh' }}>
<div className="d-flex flex-row justify-content-center nav-header">
<a href="/dashboard" className="brand-logo">
<picture>
<img src="https://user-images.githubusercontent.com/25479050/99581983-c1c18e00-29e1-11eb-9bd3-4a53585456cb.png" className="img-fluid img-thumbnail" alt="plaschema logo" />
<source media="(min-width:650px)" srcSet="https://user-images.githubusercontent.com/25479050/99581983-c1c18e00-29e1-11eb-9bd3-4a53585456cb.png" type="image/svg+xml" />
<source media="(min-width:465px)" srcSet="https://user-images.githubusercontent.com/25479050/99582047-d736b800-29e1-11eb-92f3-83dce3912e39.png" type="image/svg+xml" />
</picture>
</a>
</div>
<div className="link_container d-flex flex-column">
<button type="button" className="buttonTrue" ref={postedRef} onClick={() => { handleColor('#f4f2f6'); }}>
<Link to="/">
<i className="lni lni-dashboard" />
<span className="link_name">Dashboard</span>
</Link>
</button>
<button type="button" className={btnEn ? 'buttonTrue' : 'buttonFalse'}>
<Link to="/enroll">
<i className="lni lni-tab" />
<span className="link_name">Enrollment</span>
</Link>
</button>
<Link className=" icons accreditation-wrapper" to="/accreditation">
<i className="lni lni-checkbox" />
<span className="link_name">Accreditation</span>
</Link>
<Link className=" icons subscription-wrapper" to="/subscription">
<i className="lni lni-tab" />
<span className="link_name">Subscription</span>
</Link>
<Link className=" icons service-wrapper" to="/service">
<i className="lni lni-control-panel" />
<span className="link_name">Service Usage</span>
</Link>
<Link className=" icons report-wrapper" to="/report">
<i className="lni lni-library" />
<span className="link_name">Reports</span>
</Link>
</div>
</div>
);
}
}
export default Aside;
After setup, anytime I click on the only button I set it up on as a test, I keep getting this error page handleColor is not a function. Right now I can't think of what the issue maybe because I have tried several approaches to get it to work but the error is still there. Below is the code of the component I am trying to apply it on:
Looking forward to helpful responses. Thanks.
The question has been updated for more insight. Sorry for the earlier issues with the first iteration.
you can try with
const handleClick = () => {
or
function handleClick () {
You're wrongly referring the handleColor. handleColor is not a prop, it is a component method, you can use like this.handleColor
const { handleColor } = this.props // this is wrong, it's not a prop method
<button type="button" className="buttonTrue" ref={this.colorSwitch} onClick={() => { this.handleColor('#f4f2f6'); // this is right }}>
<Link to="/">
<i className="lni lni-dashboard" />
<span className="link_name">Dashboard</span>
</Link>
</button>
I have created sample example here with some of your code. Check out this link

React Error: Cannot read property 'map' of undefined

I have been trying to resolve this error for almost 2 hours but no luck. I have even researched and used the bind method but still no luck with mapping a props that was passed through a parent component. Your help will be greatly appreciated.
import React from "react";
import { Link } from "react-router-dom";
const PostList = ({ postItem }) => {
postItem.map((post) => (
<div className="mx-auto mb-3 card w-75" key={post.id}>
<div className="card-body">
<h5 className="card-title">{post.title}</h5>
<p className="card-text">{post.comment}</p>
<Link to="/create">
<ion-icon
style={{ color: "#fc5185", fontSize: "20px" }}
name="trash-outline"
></ion-icon>
</Link>
</div>
</div>
));
};
export default PostList;
And the parent component is
class Dashboard extends Component {
state = {
posts: [
{
id: 1,
title: "Hello",
comment: "it is sunny today",
},
],
};
createPost = (title, comment) => {
const newPost = {
id: Math.floor(Math.random() * 1000),
title,
comment,
};
this.setState({
posts: [...this.state.posts, newPost],
});
};
render() {
return (
<div>
<CreatePost createPost={this.createPost} />
<PostList postItem={this.state.posts} />
</div>
);
}
}
export default Dashboard;
I guess you have missed to add return to the PostList component, you can do it in three ways (read about arrow functions)
const PostList = ({ postItem }) => postItem.map((post) => (
<div className="mx-auto mb-3 card w-75" key={post.id}>
<div className="card-body">
<h5 className="card-title">{post.title}</h5>
<p className="card-text">{post.comment}</p>
</div>
</div>
));
const PostList = ({ postItem }) => (
postItem.map((post) => (
<div className="mx-auto mb-3 card w-75" key={post.id}>
<div className="card-body">
<h5 className="card-title">{post.title}</h5>
<p className="card-text">{post.comment}</p>
</div>
</div>
));
);
const PostList = ({ postItem }) => {
return postItem.map((post) => (
<div className="mx-auto mb-3 card w-75" key={post.id}>
<div className="card-body">
<h5 className="card-title">{post.title}</h5>
<p className="card-text">{post.comment}</p>
</div>
</div>
));
}
Here is the working example

Passing methods between Functional components in react

I have 2 components as below. When I try to pass a method (increment) from the component 'CartList' to 'CartItem' it says increment is undefined. The error occurs when I click on the button (Pointed in the below code). How can I solve this error?
Parent
import React, {Component} from 'react';
import CartItem from './CartItem';
import {connect} from "react-redux";
import Axios from "axios";
const mapStateToProps = ({ session}) => ({
session
});
const CartList = ({session, ...props}) => {
const cart = props.cart;
const increment = (productId) => {
const item = {
userId : session.userId,
productId: productId
};
Axios.post('http://localhost:5000/api/cart/increment', item)
.then(res=>{
if(res.status === 200){
console.log('Incremented');
}
})
};
return (
<div className="container-fluid">
{cart.map(item => {
return <CartItem key = {item.id} item={item} increment={increment}/>
})}
</div>
);
};
export default connect(
mapStateToProps
)(CartList);
Child
import React from 'react';
import {connect} from "react-redux";
const mapStateToProps = ({ session}) => ({
session
});
const CartItem = ({session ,...props}) => {
const {id,name, price, quantity} = props.item;
const {increment} = props.increment;
return (
<div className="row my-2 text-capitalize text-center">
<div className="col-10 mx-auto col-lg-2">
<img style={{width: '5rem', height: '5rem'}} className="img-fluid" alt="product "/>
</div>
<div className="col-10 mx-auto col-lg-2">
<span className="d-lg-none">Product: </span>{name}
</div>
<div className="col-10 mx-auto col-lg-2">
<span className="d-lg-none">Price: </span>{price}
</div>
<div className="col-10 mx-auto col-lg-2 my-2 my-lg-0">
<div className="d-flex justify-content-center">
<div>
<span className="btn btn-black mx-1" >-</span>
<span className="btn btn-black mx-1">{quantity}</span>
<span className="btn btn-black mx-1" onClick={() => increment(id)}>+</span> //<- Error occurs if I click on this button
</div>
</div>
</div>
<div className="col-10 mx-auto col-lg-2">
<div className="cart-icon" >
<i className="fas fa-trash"/>
</div>
</div>
<div className="col-10 mx-auto col-lg-2">
<srong>Total: ${50}</srong>
</div>
</div>
);
};
export default connect(
mapStateToProps
)(CartItem);
I tried implementing the function directly in the child component it is working fine. This method is responsible for incrementing the quantity of a product in the database(MongoDB). But updated value does not display. Because of that I implemented the 'increment' function within the parent component
The issue is this line:
const {increment} = props.increment;
That is trying to access props.increment.increment, which is undefined. You either meant to do
const increment = props.increment;
or
const {increment} = props;
Hi Please replace this line
Because when you destructuring props you don't need map key from props
for better understanding console your props or have a look at this document.
https://medium.com/#lcriswell/destructuring-props-in-react-b1c295005ce0
const {increment} = props.increment;
instead of
const {increment} = props;
I hope it works.
Thanks

Reactjs map function does not render the component

This is the error I am trying to render the createCardHotels function;however, whenever I run it, nothing shows up. Any help will be appreciated.
I used map function to loop through the data and whenever I run it I can see on the console that there is the data. The problem is just the rendering part.
import React, {Component} from 'react';
import {Container, Button, DropdownMenu, DropdownItem, Dropdown, DropdownToggle} from 'reactstrap';
import {Carousel} from 'react-responsive-carousel';
import styles from 'react-responsive-carousel/lib/styles/carousel.min.css';
import './selectHotel.css'
import Scroll from '../ScrollUp';
import {search} from '../../actions/search';
import {connect} from 'react-redux';
class SelectHotel extends Component{
constructor(props){
super(props);
this.state={
dropdownOpen: false,
hotels: []
};
this.toggleDropdown = this.toggleDropdown.bind(this);
}
static getDerivedStateFromProps(state, props){
if(props.hotels !== state.hotels)
return{
...state,
hotels: props.hotels
}
return null;
}
createCardHotels = () => {
return this.state.hotels.map((hotel) => {
return(
<div key={hotel._id} className="card">
<div className="row ">
<div className="col-md-4">
<Carousel autoPlay infiniteLoop>
<div>
<img src="https://placeholdit.imgix.net/~text?txtsize=38&txt=400%C3%97400&w=400&h=400" className="w-100"/>
</div>
<div>
<img src="https://placeholdit.imgix.net/~text?txtsize=38&txt=400%C3%97400&w=400&h=400" className="w-100"/>
</div>
<div>
<img src="https://placeholdit.imgix.net/~text?txtsize=38&txt=400%C3%97400&w=400&h=400" className="w-100"/>
</div>
<div>
<img src="https://placeholdit.imgix.net/~text?txtsize=38&txt=400%C3%97400&w=400&h=400" className="w-100"/>
</div>
<div>
<img src="https://placeholdit.imgix.net/~text?txtsize=38&txt=400%C3%97400&w=400&h=400" className="w-100"/>
</div>
<div>
<img src="https://placeholdit.imgix.net/~text?txtsize=38&txt=400%C3%97400&w=400&h=400" className="w-100"/>
</div>
<div>
<img src="https://placeholdit.imgix.net/~text?txtsize=38&txt=400%C3%97400&w=400&h=400" className="w-100"/>
</div>
<div>
<img src="https://placeholdit.imgix.net/~text?txtsize=38&txt=400%C3%97400&w=400&h=400" className="w-100"/>
</div>
</Carousel>
</div>
<div className="col-md-5 px-3">
<div className="card-block px-3">
<h3 className="card-title">{hotel.name}</h3>
<p className="card-text">description</p>
</div>
</div>
<div className="col-md-3 price">
<h1 className="reservation-price">$Price</h1>
<Button style={cssStyles.buttonRoom} bsStyle="primary">Choose Hotel</Button>
</div>
</div>
</div>
)}
)
}
toggleDropdown() {
this.setState(prevState => ({
dropdownOpen: !prevState.dropdownOpen
}));
}
render(){
console.log(this.state)
console.log(this.props)
return(
<div>
<Container>
<Scroll/>
<div>
<Dropdown className = 'sortbutton' size="lg" isOpen={this.state.dropdownOpen} toggle={this.toggleDropdown}>
<DropdownToggle style={{backgroundColor: "white", borderColor: "grey" , color: "black"}} caret>
Sort By:
</DropdownToggle>
<DropdownMenu>
<DropdownItem onClick={()=>{this.setSort("low");}}>
Price: Low to High
</DropdownItem>
<DropdownItem divider />
<DropdownItem onClick={()=>{this.setSort("high");}}>
Price: High to Low
</DropdownItem>
</DropdownMenu>
</Dropdown>
</div>
{this.createCardHotels()}
<br></br>
</Container>
</div>
);
}
}
const cssStyles = {
buttonRoom:{
backgroundColor: '#156bc1',
border: '1px solid #156bc1',
alignItems: 'left',
boxShadow: 'inset 0 -2px 0 #063665',
paddingLeft: '2rem',
paddingRight: '2rem',
fontSize: '0.8rem'
}
}
const mapStatetoProps = state => {
return {
hotels: state.search.hotels
};
}
export default connect(mapStatetoProps, {search})(SelectHotel);
EDIT:
This is the image from console after I put console.log(this.state), console.log(this.props), it seems like there is data in this.props and not in this.state
The issue is with add class names to JSX elements. You are using class to apply css styles with class names but class is reserved for creating class components in React so you need to use className
Wherever you see class on jsx elements change it to className
Also never forget to add key to the top parent jsx element when you render them in loop. If you have unique from data then set id from data as a key like I did below else use index as key
Change
return this.state.hotels.map((hotel) => {
return(
<div class="card">
........
To
return this.state.hotels.map((hotel) => {
return(
<div key={hotel.id} className="card">
.......
Also
Change
<h1 className="reservation-price">$Price</h1>
To
<h1 className="reservation-price">{"$Price"}</h1>
For images you need to use require or import
Change
<img src="https://placeholdit.imgix.net/~text?txtsize=38&txt=400%C3%97400&w=400&h=400" className="w-100"/>
To
<img src={require("https://placeholdit.imgix.net/~text?txtsize=38&txt=400%C3%97400&w=400&h=400")} className="w-100"/>
Do the same for other images as well
Or import it like
import text from "https://placeholdit.imgix.net/~text?txtsize=38&txt=400%C3%97400&w=400&h=400";
<img src={text} className="w-100"/>
Сould you please show your building file. May be a problem with file-loader.

Resources