onClick in React changes all of the classes states in react - javascript

I have creates a aside in react and I want to change their state to active when clicked on each of them, but when I click on any item all of them suddenly get activated. How to fix this?
import React, { useState, useEffect } from "react";
import { Col, Image, Row } from "react-bootstrap";
import "./Company.scss";
// * api
import { getCoin } from "../services/api";
// *spinner
import Loader from "./Loader";
const Company = () => {
const [changeClass, setChangeClass] = useState(false);
const [coins, setCoins] = useState([]);
useEffect(() => {
const fetchAPI = async () => {
const data = await getCoin();
setCoins(data);
};
fetchAPI();
}, []);
const myHandler = () => {
setChangeClass(true);
console.log("trued");
};
const myHandler2 = () => {
console.log();
};
return (
<>
{coins.length ? (
coins.map((coin) => (
<Row
className={
changeClass
? "p-2 border-top d-flex align-items-center company-list-single-active"
: "p-2 border-top d-flex align-items-center company-list-single"
}
onClick={() => {
myHandler();
myHandler2();
}}
key={coin.id}
>
<Col xxl="2" xl="2" lg="2" md="2" sm="2" xs="2">
<Image
src={coin.image}
alt={coin.name}
className="coin-image mx-2"
fluid
/>
</Col>
<Col>
<span>{coin.name}</span>
</Col>
</Row>
))
) : (
<Loader />
)}
</>
);
};
export default Company;

you use a test to display selected coin by the same state and it is toggled between true or false.
I added a state to save the selected coin and test on it on looping.
On the onClick we can directly update the selected item.
you cannot do that "coins.length ?" this will be always true if type of coins is array i added a test like "coins.length > 0 ?"
here the solution
import React, { useState, useEffect } from 'react';
import { Col, Image, Row } from 'react-bootstrap';
import './Company.scss';
// * api
import { getCoin } from '../services/api';
// *spinner
import Loader from './Loader';
const Company = () => {
const [selectedCoin, setSelectedCoin] = useState(null);
const [coins, setCoins] = useState([]);
useEffect(() => {
const fetchAPI = async () => {
const data = await getCoin();
setCoins(data);
};
fetchAPI();
}, []);
return (
<>
{coins.length > 0 ? (
coins.map((coin) => (
<Row
className={
selectedCoin === coin.id
? 'p-2 border-top d-flex align-items-center company-list-single-active'
: 'p-2 border-top d-flex align-items-center company-list-single'
}
onClick={() => setSelectedCoin(coin.id)}
key={coin.id}
>
<Col xxl="2" xl="2" lg="2" md="2" sm="2" xs="2">
<Image src={coin.image} alt={coin.name} className="coin-image mx-2" fluid />
</Col>
<Col>
<span>{coin.name}</span>
</Col>
</Row>
))
) : (
<Loader />
)}
</>
);
};
export default Company;

Related

Invalid hook call. Hooks can only be called inside of the body of a function component. - useContext

I have created an empty object variable named workspacesData through the context api which is available globally across the app. I am trying to set my api data to the variable within the helper function that is below (getWorkspacesData).
This function getWorkspacesData is then being called on another page of the application for when the user wants to pull in the data and have it displayed on the page. Problem is when the user presses the button I get the error "Invalid hook call. Hooks can only be called inside of the body of a function component."
I know the issue is that I am using the useContext hook within this function, but how do I get around this issue? as I want to use the globally available variable to set the data to it.
getWorkspaces.js
import { useContext } from "react";
import { AppContext } from "../../../context/context";
import mavenlinkAPI from "../apiTools";
const GetWorkspaces = async (mavenlinkAccessToken) => {
const {setWorkspacesData} = useContext(AppContext);
try{
const data = await mavenlinkAPI(
'get',
'workspaces?token='+mavenlinkAccessToken,
);
console.log(data)
setWorkspacesData(data);
} catch (error) {
console.log(error)
}
}
export default GetWorkspaces;
MavenlinkPage.jsx
import { Container, Grid, Paper } from '#mui/material';
import React, {useContext, useEffect, useRef, useState} from 'react';
import { getAuth } from "firebase/auth";
import Fab from '#mui/material/Fab';
import AddIcon from '#mui/icons-material/Add';
import {SuccessSnackbar, ErrorSnackbar} from '../components/PopupSnackbar';
import { AppContext } from '../context/context';
import GetWorkspaces from '../helpers/api/mavenlink/getWorkspaces';
import GetTimesheets from '../helpers/api/mavenlink/getTimesheets';
import GetUsers from '../helpers/api/mavenlink/getUsers';
import CreateProject from '../helpers/api/mavenlink/createProject';
import GetMavenlinkAccessToken from '../helpers/api/mavenlink/getMavenlinkAccessToken';
import DummyDataHolder from '../components/dummyDataHolder';
// import { DataGrid } from '#material-ui/x-data-grid';
export const MavenlinkPage = () => {
const { mavenlinkConnected } = useContext(AppContext);
const [errorAlert, setErrorAlert] = useState(false);
const [successAlert, setSuccessAlert] = useState(false);
const { mavenlinkAccessToken, setMavenlinkAccessToken } = useContext(AppContext);
const { workspacesData } = useContext(AppContext);
const auth = getAuth();
const user = auth.currentUser;
const uid = user.uid
const handleAlertClose = (event, reason) => {
if (reason === 'clickaway') {
return;
}
setSuccessAlert(false) && setErrorAlert(false);
};
useEffect(() => {
if(mavenlinkConnected){
GetMavenlinkAccessToken(setMavenlinkAccessToken);
}
}, [])
console.log(mavenlinkAccessToken)
return(
<>
<Container>
<div className="mavenlink-page">
<Grid container spacing={2}>
<Grid item xs={12}>
<h1>Mavenlink</h1>
</Grid>
<Grid item xs={12}>
<Paper className="connection-status" elevation={1}>
<h4 className="title">Connection Status:</h4>
{!mavenlinkConnected ? <h4 className="response-error">{user.email} is not connected</h4> : <h4 className="response-success">{user.email} is connected</h4>}
</Paper>
</Grid>
<Grid item xs={12}>
<Paper elevation={1}>
<h4>Get Workspaces</h4>
<Fab onClick={() => GetWorkspaces(mavenlinkAccessToken)} color="primary" aria-label="add">
<AddIcon />
</Fab>
<h4>Get timesheets</h4>
<Fab onClick={() => GetTimesheets(mavenlinkAccessToken)} color="primary" aria-label="add">
<AddIcon />
</Fab>
<h4>Get users</h4>
<Fab onClick={() => GetUsers(mavenlinkAccessToken)} color="primary" aria-label="add">
<AddIcon />
</Fab>
<h4>Create project</h4>
<Fab onClick={() => CreateProject(mavenlinkAccessToken)} color="primary" aria-label="add">
<AddIcon />
</Fab>
</Paper>
</Grid>
<Grid item xs={12}>
<Paper elevation={10} style={{ height: 400, width: '100%' }}>
{workspacesData != null ?
Object.keys(workspacesData).map((item, index) => {
return(
<div key={index}>
{workspacesData[item].map((m, ind) =>
<div key={ind}>{item}</div>
)}
</div>
)
})
:
<div></div>
}
</Paper>
</Grid>
</Grid>
</div>
{successAlert === true ? <SuccessSnackbar open={successAlert} handleClose={handleAlertClose}/> : <></> }
{errorAlert === true ? <ErrorSnackbar open={errorAlert} handleClose={handleAlertClose}/> : <></> }
</Container>
</>
);
};
You can call the hook inside your component and pass the returned value from it to the function:
const getWorkspaces = async (mavenlinkAccessToken, onSuccess) => {
try{
const data = await mavenlinkAPI(
'get',
'workspaces?token='+mavenlinkAccessToken,
);
onSuccess?.(data)
} catch (error) {
console.log(error)
}
}
And call it as:
export const MavenlinkPage = () => {
const { setWorkspacesData } = useContext(AppContext);
...
onClick={() => getWorkspaces(mavenlinkAccessToken, setWorkspacesData )}
}
Or create a custom hook:
const useGetWorkspaces = (mavenlinkAccessToken) => {
const { setWorkspacesData } = useContext(AppContext);
return async () => {
try{
const data = await mavenlinkAPI(
'get',
'workspaces?token='+mavenlinkAccessToken,
);
setWorkspacesData(data);
} catch (error) {
console.log(error)
}
}
}
And use it like:
export const MavenlinkPage = () => {
const getWorkspaces = useGetWorkspaces(mavenlinkAccessToken);
...
onClick={() => getWorkspaces()}
}

Uncaught ReferenceError: Cannot access 'ordersToDisplay' before initialization - trying to update value on re-render React

I am trying to set the title of my document to "/{orderNumber}orders" and for that orderNumber value to update every time user clicks the button and different number of orders from filtered array are displayed on the screen.
For context, I am importing a json file, filtering it to display the correct elements I want decided by user input, and I am then calculating the length of that array, of which that integer needs to be stored in orderNumber variable to update document title.
I know I am accessing the correct value of the arrays as I have console logged it, my issue is how to update this state change every re render without this error throwing: (Uncaught ReferenceError: Cannot access 'ordersToDisplay' before initialization)
Code:
import { Col, Row } from "antd";
import { useContext, useEffect, useMemo, useState } from "react";
import Order from "../components/Order";
import { AppContext } from "../context/Context";
import AntButton from "../elements/Button";
import ordersToDisplay from "../orders.json";
const OrdersPage = () => {
const [filteringStatus, setFilteringStatus] = useState("");
const {orderAmount, setOrderAmount} = useContext(AppContext)
const [test, setTest] = useState("")
const setDiplayAcceptedOrders = () => {
setFilteringStatus("accepted");
setTest(ordersToDisplay.length)
};
const setDiplayCompletedOrders = () => {
setFilteringStatus("complete");
setTest(ordersToDisplay.length)
};
const setDiplayInProgressOrders = () => {
setFilteringStatus("inProgress");
setTest(ordersToDisplay.length)
};
const ordersToDisplay = useMemo(() => {
if (filteringStatus) {
return ordersToDisplay.filter((i) => i.orderStatus === filteringStatus);
}
return ordersToDisplay;
}, [filteringStatus]);
console.log("Orders to display: ", ordersToDisplay);
console.log("test value: ", test)
return(
<div className="container">
<Row justify="space-between" align="middle">
<Col span={6}>
<h1>Orders</h1>
</Col>
<Col span={6}>
<AntButton onClick={setDiplayAcceptedOrders} name="Accepted"/>
</Col>
<Col span={6}>
<AntButton onClick={setDiplayInProgressOrders} name="In Progress"/>
</Col>
<Col span={6}>
<AntButton onClick={setDiplayCompletedOrders} name="Complete"/>
</Col>
</Row>
<Row>
<Col span={12}>
<h3>{filteringStatus == "" ? "All Orders" : filteringStatus}</h3>
{ordersToDisplay.map((e) => {
return(
<Order
key={e.id}
productName={e.productName}
dateOrdered={e.dateOrdered}
orderStatus={e.orderStatus}
/>
)
})}
</Col>
</Row>
</div>
)
}
export default OrdersPage;
app
const App = () => {
const [orderAmount, setOrderAmount] = useState("")
const Routes = useRoutes([
{path: "/", element: <HomePage/>},
{path: `/(${orderAmount})orders`, element: <OrdersPage/>}
])
return (
<AppContext.Provider value={{
orderAmount, setOrderAmount
}}>
<div>
{Routes}
</div>
</AppContext.Provider>
);
};
export default App;
You are masking the imported ordersToDisplay with what you are trying to memoize. Rename the memoized version/variable. You need only store in state the current filteringStatus state, the test state seems unnecessary and isn't used from what I see.
To update the orderAmount state in the context, use a useEffect hook with a dependency on the computed/memoized orders value to issue a side-effect to update the orderAmount value.
Example:
import { Col, Row } from "antd";
import { useContext, useEffect, useMemo, useState } from "react";
import Order from "../components/Order";
import { AppContext } from "../context/Context";
import AntButton from "../elements/Button";
import ordersToDisplay from "../orders.json";
const OrdersPage = () => {
const [filteringStatus, setFilteringStatus] = useState("");
const { orderAmount, setOrderAmount } = useContext(AppContext);
const setDiplayAcceptedOrders = () => {
setFilteringStatus("accepted");
};
const setDiplayCompletedOrders = () => {
setFilteringStatus("complete");
};
const setDiplayInProgressOrders = () => {
setFilteringStatus("inProgress");
};
// rename to something else, anything but ordersToDisplay
const orders = useMemo(() => {
if (filteringStatus) {
return ordersToDisplay.filter((i) => i.orderStatus === filteringStatus);
}
return ordersToDisplay;
}, [filteringStatus]);
useEffect(() => {
console.log("Orders to display: ", orders); // <-- output derived value
// update amount when orders array updates
setOrderAmount(orders.length);
}, [orders, setOrderAmount]);
return (
<div className="container">
<Row justify="space-between" align="middle">
<Col span={6}>
<h1>Orders</h1>
</Col>
<Col span={6}>
<AntButton onClick={setDiplayAcceptedOrders} name="Accepted"/>
</Col>
<Col span={6}>
<AntButton onClick={setDiplayInProgressOrders} name="In Progress"/>
</Col>
<Col span={6}>
<AntButton onClick={setDiplayCompletedOrders} name="Complete"/>
</Col>
</Row>
<Row>
<Col span={12}>
<h3>{filteringStatus == "" ? "All Orders" : filteringStatus}</h3>
{orders.map((e) => { // <-- use here
return (
<Order
key={e.id}
productName={e.productName}
dateOrdered={e.dateOrdered}
orderStatus={e.orderStatus}
/>
)
})}
</Col>
</Row>
</div>
);
};
export default OrdersPage;

why is useEffect running on first render?

I have a MERN react component that is going to show a toast to my user after they create a new group.
Here is my useEffect below
useEffect(() => {
toast(
<Fragment>
New Group Created
</Fragment>
);
}, [successCreate]);
I only want this useEffect to run AFTER my user creates a new group.
It currently runs on first render, and after my user clicks the modal(child) then triggers the successCreate from redux(just creates a new group).
How can I make useEffect run only when successCreate is called.. NOT on first render AND successCreate
Here is my component
import React, { Fragment, useState, useEffect, useContext } from 'react';
import WizardInput from '../auth/wizard/WizardInput';
import {useDispatch, useSelector} from 'react-redux';
import {
Button,
Card,
CardBody,
Form,
Label,
Input,
Media,
Modal,
ModalBody,
ModalHeader
} from 'reactstrap';
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome';
import Select from 'react-select';
import { toast } from 'react-toastify';
import makeAnimated from 'react-select/animated';
import {listGroups, createGroup} from '../../actions/index';
//import { isIterableArray } from '../../helpers/utils';
import { CsvUploadContext } from '../../context/Context';
import chroma from 'chroma'
const StepOneForm = ({ register, errors, watch}) => {
const { upload, setUpload } = useContext(CsvUploadContext);
//const { handleInputChange } = useContext(CsvUploadContext);
const [ createGroupModal, setCreateGroupModal ] = useState(false)
const [newGroup, setNewGroup] = useState({
title: ''
})
const dispatch = useDispatch();
const groups = useSelector(state => state.groups)
const groupCreate = useSelector((state) => state.groupCreate)
const {success: successCreate} = groupCreate
const animatedComponents = makeAnimated();
useEffect(() => {
dispatch(listGroups())
}, [successCreate])
useEffect(() => {
toast(
<Fragment>
New Group Created
</Fragment>
);
}, [successCreate]);
const customStyles = {
control: (base, state) => ({
...base,
background: "light",
// match with the menu
borderRadius: state.isFocused ? "3px 3px 0 0" : 3,
// Overwrittes the different states of border
borderColor: state.isFocused ? "primary" : "light",
// Removes weird border around container
boxShadow: state.isFocused ? null : null,
"&:hover": {
// Overwrittes the different states of border
borderColor: state.isFocused ? "blue" : "#2c7be5"
}
}),
menu: base => ({
...base,
// override border radius to match the box
borderRadius: 0,
// kill the gap
marginTop: 0
}),
menuList: base => ({
...base,
// kill the white space on first and last option
padding: 0,
color: 'f9fafd'
}),
option: (styles, { data, isDisabled, isFocused, isSelected }) => {
const color = chroma(data.color);
return {
...styles,
backgroundColor: isDisabled
? null
: isSelected
? data.color
: isFocused,
color: '232e3c',
};
}
};
const toggle = () => { setCreateGroupModal(!createGroupModal)}
const closeBtn = (
<button className="close font-weight-normal" onClick={toggle}>
×
</button>
);
const handleSubmit = (e) => {
e.preventDefault()
dispatch(createGroup(newGroup))
setCreateGroupModal(false)
};
console.log(upload?.group)
const handleChange = e => {
setNewGroup({...newGroup, [e.target.name]: e.target.value})
}
return (
<Fragment>
<Media className="flex-center pb-3 d-block d-md-flex text-center mb-2">
<Media body className="ml-md-4">
</Media>
</Media>
<h4 className="mb-1 text-center">Choose Groups</h4>
<p className=" text-center fs-0">These groups will contain your contacts after import</p>
<Select
name="group"
required={true}
className="mb-3"
styles={customStyles}
components={animatedComponents}
innerRef={register({
required: true
})}
closeMenuOnSelect={true}
options={groups}
getOptionLabel={({title}) => title}
getOptionValue={({_id}) => _id}
onChange={(_id) => setUpload({...upload, group: _id})}
isMulti
placeholder="select group"
isSearchable={true}
errors={errors}
/>
<Button color="light" onClick={(() => setCreateGroupModal(true))} className="rounded-capsule shadow-none fs--1 ml- mb-0" >
<FontAwesomeIcon icon="user-plus" />
{` or create a new group`}
</Button>
<Modal isOpen={createGroupModal} centered toggle={() => setCreateGroupModal(!createGroupModal)}>
<ModalHeader toggle={toggle} className="bg-light d-flex flex-between-center border-bottom-0" close={closeBtn}>
Let's give the group a name
</ModalHeader>
<ModalBody className="p-0">
<Card>
<CardBody className="fs--1 font-weight-normal p-4">
<Card>
<CardBody className="fs--1 font-weight-normal p-4">
<Form onSubmit={handleSubmit}>
<Label for="title">Group Name:</Label>
<Input value={newGroup.title.value} onChange={handleChange} className="mb-3" name="title" id="title"/>
<Button block onClick={handleSubmit} color="primary" className="mb-3">Save</Button>
</Form>
</CardBody>
</Card>
<Button block onClick={() => setCreateGroupModal(false)}>close</Button>
</CardBody>
</Card>
</ModalBody>
</Modal>
<WizardInput
type="textarea"
label="or add number manually seperated by comma"
placeholder="+17209908576, +18165009878, +19138683784"
name="manual-add"
rows="4"
id="manual-add"
innerRef={register({
required: false
})}
errors={errors}
/>
</Fragment>
);
};
export default StepOneForm;
Is successCreate a boolean?
This would work:
useEffect(() => {
if(!successCreate) return;
toast(
<Fragment>
New Group Created
</Fragment>
);
}, [successCreate]);
useEffect is always called when the dependencies change - on first render it is guaranteed to be called because there is nothing previous - this is the equivalent to componentDidMount
useEffect(() => {
console.log('mounted');
},[]);

Search Box implementation and filter posts?

I've written the code to filter the post in the useEffect. I can't find a way to implement it. I already have 5 posts in my database. I'm bringing all 5 posts using useSelector but I can't find a way to filter while I am typing in the search bar. If I try to set the filtered value in the setListsPosts2(filteredPostList) when fetching those data using the map I didn't get my all posts.
when I do const [listPosts2, setListPosts2] = useState([posts]); it started continues loop and giving error also as asking me add posts in the lists of useEffect dependencies but when i add it it started continues loop of error
here is my homepage.js file
import { useEffect, useState } from 'react';
import { Col, Container, Form, Row } from 'react-bootstrap';
import { ToastContainer } from 'react-toastify';
import { useDispatch, useSelector } from 'react-redux';
import { listPosts } from '../actions/postActions';
import Banner from '../components/Banner';
import Post from '../components/Post';
import Paginate from '../components/Paginate';
const HomePage = ({ match }) => {
const [keyword, setKeyword] = useState('');
const [listPosts2, setListPosts2] = useState([]);
const pageNumber = match.params.pageNumber || 1;
const dispatch = useDispatch();
const postLists = useSelector((state) => state.postLists);
const { posts, pages, page } = postLists;
const postCreate = useSelector((state) => state.postCreate);
const { success: successCreate } = postCreate;
const postUpdate = useSelector((state) => state.postUpdate);
const { success: successUpdate } = postUpdate;
const postDelete = useSelector((state) => state.postDelete);
const { success: deleteSuccess } = postDelete;
useEffect(() => {
const filteredPostList = posts?.filter((post) =>
post.title.toLowerCase().includes(keyword.toLowerCase())
);
setListPosts2(filteredPostList);
dispatch(listPosts(pageNumber));
}, [dispatch, pageNumber, deleteSuccess, successCreate, successUpdate]);
return (
<div>
<ToastContainer />
<Banner />
<div className="my-3">
<Container id="posts">
<Form className="searchBoxForm">
<Form.Control
type="text"
name="q"
onChange={(e) => setKeyword(e.target.value)}
placeholder="Search Posts..."></Form.Control>
</Form>
<h2 className="mt-3" style={{ letterSpacing: '4px' }}>
POSTS
</h2>
<Row className="mt-3">
<Col>
<Row>
{posts
?.map((post) => (
<Col key={post._id} md={3} sm={4}>
<Post post={post} />
</Col>
))
.sort()
.reverse()}
</Row>
<Paginate pages={pages} page={page} />
</Col>
</Row>
</Container>
</div>
</div>
);
};
export default HomePage;

can't render the products in proper order using nested map() & useEffect() in reactjs

I'm trying to build a restaurant web-app with Reactjs. I've parent categories, child categories, and products under child categories, I'm trying to build a UI with tabs where I can show the parent categories-clicked-show child categories & show the products under that child categories in proper order.
I'm getting the child categories when the parent is clicked, but I'm not getting the products as expected.
I want to render the product like this
Burger
Show all the burgers
Sandwich
show all the sandwich,
swarma
show all the sawrmas,
but instead im getting the swarmas only where i should get all the products in proper order.
Plz help me get the products in proper order.
This is my Menu.js
import React, { useEffect } from "react";
import MenuItems from "./MenuItems";
import "./testmenu.css";
// import burger from "../images/burger.jpg";
// import cake from "../images/cake-2.jpeg";
//Bootsrap
import { Container, Row, Col, Tab, Nav } from "react-bootstrap";
//REDUX
import { useSelector, useDispatch } from "react-redux";
import { getAllCategory } from "../actions";
import { Fragment } from "react";
const TestMenu = () => {
//GET ALL CATEGORIES WHEN RENDERED
const category = useSelector((state) => state.category);
console.log(category);
const dispatch = useDispatch();
useEffect(() => {
dispatch(getAllCategory());
}, [dispatch]);
const renderParentCategories = (categories) => {
let parentCategories = [];
for (let category of categories) {
parentCategories.push(
<Nav.Item key={category.name}>
<Nav.Link eventKey={category.name}>{category.name}</Nav.Link>
</Nav.Item>
);
}
return parentCategories;
};
const renderChildrenCategories = (categories) => {
console.log(categories);
return categories.map((category, i) => (
<Tab.Pane key={i} eventKey={category.name}>
{category.children.map((cat, i) => (
<Fragment key={i}>
<h2>{cat.name}</h2>
<Row>{<MenuItems slug={cat.slug} />}</Row>
</Fragment>
))}
</Tab.Pane>
));
};
//CALLING THE LIST OF THE ITEMS
return (
<div className="Collections">
<Container>
<Tab.Container defaultActiveKey="first">
<Row>
<Col>
<Nav className="d-flex flex-row justify-content-center text-center">
{category.categories.length > 0
? renderParentCategories(category.categories)
: null}
</Nav>
</Col>
</Row>
<Row>
<Col>
<Tab.Content>
{category.categories.length > 0
? renderChildrenCategories(category.categories)
: null}
</Tab.Content>
</Col>
</Row>
</Tab.Container>
</Container>
</div>
);
};
export default TestMenu;
This is my MenuItems.js file:
import React, { useEffect } from "react";
import { Button, ButtonGroup, Col } from "react-bootstrap";
import { useDispatch, useSelector } from "react-redux";
import { addToCart, getProductsBySlug } from "../actions";
import { generatePublicUrl } from "../urlConfig";
const MenuItems = ({ slug }) => {
const product = useSelector((state) => state.product);
const dispatch = useDispatch();
console.log(product);
useEffect(() => {
dispatch(getProductsBySlug(slug));
}, [dispatch, slug]);
return product.products.map((product, i) => (
<Col key={i} xs={6} md={3} lg={3} xl={3}>
<div className="menuitem">
<div className="images">
<img
className="image"
src={generatePublicUrl(product.productPictures[0].img)}
alt="img"
/>
<div className="menuitem__buttons">
<ButtonGroup size="sm">
{/* onClick={props.itemInfo} */}
<Button variant="info">
<i className="fa fa-info-circle" aria-hidden="true" />
Info
</Button>
{/* onClick={props.addItem} */}
<Button
variant="success"
onClick={() => {
const { _id, name, price } = product;
const img = product.productPictures[0].img;
// console.log(_id, name, price, img);
dispatch(addToCart( _id, name, price, img ));
}}
>
<i className="fas fa-shopping-cart" />
Add
</Button>
</ButtonGroup>
</div>
<span className="images__h3">
<h5 style={{ textAlign: "center" }}>{product.name}</h5>
<h5
style={{
color: "green",
textAlign: "center",
fontSize: "16px",
}}
>
Price: {product.price}tk
</h5>
</span>
</div>
</div>
</Col>
));
};
export default MenuItems;
Here is the console:
Here is the result I'm getting:

Categories