useState not updating data when passing from parent function component using ref - reactjs

I am trying to send data to child function component where I am binding form fields with that data. It works fine on first call, but when I am calling 2nd time the data never update in state, its always shows the first one.
This is parent which use the ref of child component
export default function Form1() {
const [count, setCount] = useState(0);
const [counter, setCounter] = useState(10);
const AddNewRef = useRef();
const clickMe=() => {
setCount(count+1);
setCounter(counter*2);
AddNewRef.current.showDrawer(counter*2);
}
return (
<div>
<p>You clicked count: {count} & counter: {counter} times</p>
{
count > 10 ?
(
<p className='red'>your count is greater then 10</p>
) :
(
<p className='green'>your count is less then 10</p>
)
}
<button onClick={() => clickMe()}>
Click me
</button>
<AddNew ref={AddNewRef} Count={count} Counter={counter} />
</div>
)
}
This is child component
const AddNew=forwardRef((props, ref) => {
const[objCounter, setobjCounter] = useState(null);
useImperativeHandle(
ref,
() => ({
showDrawer(count) {
setobjCounter(count);
//only shows at first click at parent, Not updating on 2nd, 3rd click from parent and so on....
}
}),
)
return (
<>
<Drawer
title={<span> <i className='fa-solid fa-kaaba' /> Haj Setup Form</span>}
width={window.innerWidth > 900 ? 800 : window.innerWidth - 50}
onClose={onClose}
visible={visible}
bodyStyle={{ paddingBottom: 80 }}
extra={
<Space>
<Button onClick={onClose}>Cancel</Button>
<Button onClick={onClose} type="primary">
Submit
</Button>
</Space>
}
>
<Form
style={{display: formVisible ? 'block' : 'none'}}
form={form}
layout="vertical"
onFinish={onFinish}
onFinishFailed={onFinishFailed}
autoComplete="off"
hideRequiredMark>
<Row gutter={16}>
<Col xs={24} sm={24} md={24} lg={24}>
<Form.Item
name="packageName"
label="Package Name"
rules={[{ required: true, message: 'Please enter package name' }]}
initialValue={objCounter}
>
<Input style={{width: '100%'}}
maxLength={100} />
</Form.Item>
</Col>
</Row>
</Form>
</Drawer>
</>
)
});
export default AddNew

Since the state updates are working and you are simply wanting to update the form field, you can use the returned form reference from the useForm hook to update the form state. In this case, update the packageName field.
const AddNew = forwardRef((props, ref) => {
const [objCounter, setobjCounter] = useState(13);
const [visible, setVisible] = useState(false);
const [formVisible, setformVisible] = useState(true);
const [form] = Form.useForm();
useImperativeHandle(ref, () => ({
showDrawer(count) {
setobjCounter(count);
setVisible(true);
form.setFieldsValue({
packageName: count // <-- update the specific field
});
}
}));
const onClose = () => {
setVisible(false);
};
return (
...
);
});

Related

How to update existing data from DB with react-hook-form

I'm creating an E-commerce like website, we upload products through the admin site.
I have Upload.tsx file like so:
...
import FormDetails from '#components/FormDetails';
const Upload: React.FC = () => {
const { register, handleSubmit, reset, unregister, watch, setValue } =
useForm<UploadFormState>();
const watchPacksOrWholesale = watch('packsOrWholesale');
const [uploadLoading, setUploadLoading] = useState<boolean>(false);
const [file, setFile] = useState<File | null>(null);
const [url, setUrl] = useState<string>('');
const [progress, setProgress] = useState<number>(0);
const [createdAt, setCreatedAt] = useState<Timestamp | null>(null);
const saveProduct = useProductStore((state) => state.saveProduct);
const isLoading = useProductStore((state) => state.isLoadingSave);
const handleProductSubmit: SubmitHandler<UploadFormState> = (data) => {
const newProductUpload = {
drinkName: data.drinkName,
description: data.description,
category: data.category,
price: Number(data.price),
url,
createdAt,
packsOrWholesale: data.packsOrWholesale,
packSize: data.packSize,
};
saveProduct(newProductUpload, reset, setFile);
};
return (
<>
<Text fontSize="xl" mb={5} fontWeight="semibold">
Upload Drinks
</Text>
<form onSubmit={handleSubmit(handleProductSubmit)}>
<FormDetails
register={register}
file={file}
progress={progress}
setFile={setFile}
setProgress={setProgress}
isRequired={true}
unregister={unregister}
watchPacksOrWholesale={watchPacksOrWholesale}
setValue={setValue}
/>
<ButtonGroup mt={4} spacing={2}>
<Button
size="sm"
isLoading={uploadLoading}
isDisabled={!file || progress === 100}
onClick={handleProductImageUpload}
>
Upload Image
</Button>
<Button
size="sm"
type="submit"
variant="solid"
// isDisabled={!file || progress === 0}
colorScheme="success"
isLoading={isLoading}
>
Save Product
</Button>
</ButtonGroup>
</form>
</>
);
};
export default Upload;
.....
FormDetails.tsx
import {
....
} from '#chakra-ui/react';
import { FileInput } from '#components/FormFields';
import { drinkCategoriesArray } from '#data/index';
import { FormDetailsProps } from '#interfaces/index';
import { useEffect, useState } from 'react';
import { Controller } from 'react-hook-form';
const FormDetails: React.FC<FormDetailsProps> = ({
....
}) => {
const [isPacksOrWholesale, setIsPacksOrWholesale] = useState<boolean>(
product?.packsOrWholesale || false
);
useEffect(() => {
if (watchPacksOrWholesale) {
register('packsOrWholesale', { required: true });
} else {
unregister('packsOrWholesale');
}
}, [register, unregister, watchPacksOrWholesale, isPacksOrWholesale]);
return (
<>
<SimpleGrid columns={{ base: 1, sm: 2 }} spacing={6} textAlign="left">
<FormControl>
<FormLabel fontSize="14px">Drink name</FormLabel>
<Input
{...register('drinkName', { required: isRequired })}
type={'text'}
placeholder="Meridian"
defaultValue={(showValue && product?.drinkName) || ''}
/>
</FormControl>
<FormControl>
<FormLabel fontSize="14px">Description</FormLabel>
<Input
{...register('description', { required: isRequired })}
type={'text'}
placeholder="Meridian wine is the best"
defaultValue={(showValue && product?.description) || ''}
/>
</FormControl>
<FormControl>
<FormLabel fontSize="14px">Select Category</FormLabel>
<Select
{...register('category', { required: isRequired })}
placeholder="Select category"
defaultValue={(showValue && product?.category) || ''}
>
{drinkCategoriesArray.map(({ drinkCategory, drink_id }) => (
<option key={drink_id} value={drinkCategory}>
{drinkCategory}
</option>
))}
</Select>
</FormControl>
<FormControl>
<FormLabel>
<FormLabel fontSize="14px">Select Product method</FormLabel>
<HStack>
<Text fontWeight={'semibold'}>Product in wholesale</Text>
<Switch
id="packs switch"
{...register('packsOrWholesale')}
colorScheme={'primary'}
size={'sm'}
fontWeight={'semibold'}
defaultChecked={showValue && product?.packsOrWholesale}
isChecked={isPacksOrWholesale}
onChange={() => setIsPacksOrWholesale(!isPacksOrWholesale)}
/>
<Text fontWeight={'semibold'}>Product in packs</Text>
</HStack>
</FormLabel>
</FormControl>
{isPacksOrWholesale ? (
<FormControl>
<FormLabel>
<FormLabel fontSize="14px">Select pack size</FormLabel>
<Select
{...register('packSize', {
required: true,
})}
placeholder="Select Pack Size"
defaultValue={(showValue && product?.packSize) || ''}
>
<option value="6 Packs">6 Packs</option>
<option value="12 Packs">12 Packs</option>
</Select>
</FormLabel>
</FormControl>
) : null}
<FormControl mt={'3px'}>
<FormLabel fontSize="14px">Price</FormLabel>
<Input
{...register('price', { required: isRequired })}
type="number"
placeholder="500 (in Dollars)"
defaultValue={(showValue && product?.price) || ''}
/>
</FormControl>
</SimpleGrid>
....
</Box>
</>
);
};
export default FormDetails;
.....
ProductEdit.tsx
import FormDetails from '#components/FormDetails';
import { useProductStore } from '#store/useProductStore';
const ProductEdit = forwardRef(({ product }: ProductType, ref) => {
const { id } = useParams<ProductParams>();
const { register, handleSubmit, watch, unregister, reset, setValue } =
useForm<UploadFormState>();
const watchPacksOrWholesale = watch('packsOrWholesale');
const [file, setFile] = useState<File | null>(null);
const [uploadLoading, setUploadLoading] = useState<boolean>(false);
const [url, setUrl] = useState<string>('');
const [progress, setProgress] = useState<number>(0);
const { isOpen, onOpen, onClose } = useDisclosure();
const editProduct = useProductStore((state) => state.editProduct);
const isLoading = useProductStore((state) => state.isLoadingEdit);
const handleProductUpdate: SubmitHandler<UploadFormState> = (data) => {
const newUpdate = {
drinkName: data.drinkName || product?.drinkName,
description: data.description || product?.description,
category: data.category || product?.category,
url: url || product?.url,
price: Number(data.price) || Number(product?.price),
packsOrWholesale: data.packsOrWholesale || product?.packsOrWholesale,
packSize: data.packSize || product?.packSize,
};
// editProduct(id, newUpdate, onClose, setFile);
console.log(newUpdate);
};
return (
<Box>
<IconButton
aria-label="edit-button"
size="sm"
colorScheme="secondary"
variant="ghost"
onClick={onOpen}
icon={<RiPencilLine size="18px" />}
/>
<Modal
isCentered
size="lg"
onClose={onClose}
isOpen={isOpen}
motionPreset="slideInBottom"
closeOnOverlayClick={false}
>
<ModalOverlay backdropFilter={'blur(5px)'} />
<ModalContent>
<ModalHeader>
Edit Product{' '}
<chakra.span color="success.700">{product?.drinkName}</chakra.span>?
</ModalHeader>
<ModalCloseButton size="sm" />
<form onSubmit={handleSubmit(handleProductUpdate)}>
<ModalBody>
<FormDetails
register={register}
file={file}
progress={progress}
setFile={setFile}
setProgress={setProgress}
showValue={true}
isRequired={false}
product={product}
unregister={unregister}
watchPacksOrWholesale={watchPacksOrWholesale}
setValue={setValue}
/>
</ModalBody>
<ModalFooter>
<ButtonGroup mt={4} spacing={2}>
<Button
isLoading={uploadLoading}
onClick={handleProductImageUpload}
isDisabled={!file || progress === 100}
size="sm"
>
Upload Image
</Button>
<Button
size="sm"
type="submit"
variant="solid"
isLoading={isLoading}
colorScheme="success"
>
Update Product
</Button>
</ButtonGroup>
</ModalFooter>
</form>
</ModalContent>
</Modal>
</Box>
);
});
export default ProductEdit;
I have a reusable component, called FormDetails. I use this component to get the data from the admin input and do an upload. Alternatively, I also use it for the ProductEdit component.
Everything works fine, except for the fact that,
in the FormDetails component, I want to use react-hook-form to manage the state of what renders. i.e if watchPacksOrWholesale is true, which is linked to the Switch component, the Select component which holds the packSize should show.
The ProductEdit component picks the existing Product from firebase and then on editing the product using react-hook-form if I disable the Switch component the value for the PackSize should be an empty string, meaning I don't want a packSize. I should be able to update the product on Firebase.
All I'm saying is that the Switch component does not update well.

Why my checkbox doesn't work in my Dialog?

I create a component for my Dialog and my Checkbox my issue is when my checkbox is not in the Dialog the update works but when it's inside it doesn't work. I don't understand why.
const Popup = ({ title, handleClose, openned, children }) => {
return (
<Dialog className='react-popup-template' fullWidth={true} maxWidth='sm' open={openned} onClose={handleClose} aria-labelledby="parent-modal-title" aria-describedby="parent-modal-description">
<DialogContent id="modal-description" >
<div>
{title && <div><h4 style={{ textAlign: 'center', fontWeight: 'bold', fontSize : '23px' }}>{title}</h4><br/></div>}
{children}
</div>
</DialogContent>
</Dialog>
);
}
const CheckBox = (value, onChange) => {
return (
<label>
<input type='checkbox' value={value} onChange={onChange} />
</label>)
}
const App = () =>{
const [openPopup, setOpenPopup] = React.useState(false)
const [checked, setChecked] = React.useState(false)
const [title, setTitle] = React.useState('')
const [description, setDescription] = React.useState('')
const showModal = (title) =>{
setTitle(title)
setDescription(<CheckBox value={checked} onChange={() => {setChecked(!checked)}} />)
}
return (
<button onClick={() => {showModal('Title')}}>showModal</button>
<PopupTemplate title={title} handleClose={() => { setOpenPopup(false) }} openned={openPopup}>
{description}
</PopupTemplate>)
}
In your Checkbox you should either destructure your props
const CheckBox = ({ value, onChange }) => {
return (
<label>
<input type="checkbox" value={value} onChange={onChange} />
</label>
);
};
Or use your props via the props value
const CheckBox = (props) => {
return (
<label>
<input type="checkbox" value={props.value} onChange={props.onChange} />
</label>
);
};
EDIT:
The state only updates the first time you click the checkbox. Using the callback in the setChecked method will solve this.
...
setDescription(
<CheckBox
value={checked}
onChange={() => {
setChecked((prevChecked) => !prevChecked);
}}
/>
);
...
PS: I don't now if its just a copy/paste error, but you're missing setOpenPopup(true) in your showModal function.
Try this, as mui uses forwarRef for its components this should work,
setDescription(<CheckBox checked={checked} onChange={e => setChecked(!checked)} />)

How to use a function on onClick instead of onChange?

i have an search function for searching in the table. Now. I want to use the search function on the onClick of the icon instead of the onChange of the input field. I don't think i need the throttle for that. I try to use the function setGlobalFilter directly inside the handleClick but it won't work
function GlobalFilter({ globalFilter, setGlobalFilter }) {
const [value, setValue] = React.useState(globalFilter)
const onChange = React.useCallback(
value => {
const throttledSetGlobalFilter = throttle(
value => {
setGlobalFilter(value || undefined)
},
2000
)
throttledSetGlobalFilter(value)
},
[setGlobalFilter]
)
return (
<span className={styles.componentGlobalFilter}>
<input
className={styles.input}
value={value || ''}
onChange={(e) => {
setValue(e.target.value)
onChange(e.target.value)
}}
placeholder={`Zoek in deze tabel`}
/>
<Icon onClick={handleClick} layoutClassName={styles.icon} {...{ icon }} />
</span>
)
function handleClick() {
}
}
If I understand your question, you want the icon click to invoke the setGlobalFilter callback with the input value. Remove the onChange handler and directly update value state. Call setGlobalFilter with the state value when the icon is clicked.
function GlobalFilter({ globalFilter, setGlobalFilter }) {
const [value, setValue] = useState(globalFilter ?? '');
const handleClick = () => setGlobalFilter(value);
return (
<span className={styles.componentGlobalFilter}>
<input
className={styles.input}
value={value}
onChange={(e) => setValue(e.target.value)}
placeholder={`Zoek in deze tabel`}
/>
<Icon onClick={handleClick} layoutClassName={styles.icon} {...{ icon }} />
</span>
);
}
If you need to throttle the setGlobalFilter then the following may help.
function GlobalFilter({ globalFilter, setGlobalFilter }) {
const [value, setValue] = useState(globalFilter ?? '');
const handleClick = throttle(
() => setGlobalFilter(value),
2000,
);
return (
<span className={styles.componentGlobalFilter}>
<input
className={styles.input}
value={value}
onChange={(e) => setValue(e.target.value)}
placeholder={`Zoek in deze tabel`}
/>
<Icon onClick={handleClick} layoutClassName={styles.icon} {...{ icon }} />
</span>
);
}

Utilizing the "Ok" button in ANTd Modal in React

I am creating a movie website that displays Modals of movies when you click on the movie card. I'm able to handle the "onCancel" which turns setActivateModal to false and closes the Modal, but I also want to allow the "Schedule" button to do something. The intended behavior is to have the "Schedule" button generate a different form in which I can fill out to "schedule" a movie with basic form entries that are then sent to my database. I'm not struggling with the form, but I'm struggling with how to handle generating one with the "Schedule" button. I'm unsure if you are allowed to do "nested" Modals, but any way it can be handled is fine.
import React, { useEffect, useState } from 'react';
import {
Layout,
Input,
Row,
Col,
Card,
Tag,
Spin,
Modal,
Typography,
Button,
} from 'antd';
import 'antd/dist/antd.css';
const { Content } = Layout;
const { Search } = Input;
const { Meta } = Card;
const TextTitle = Typography.Title;
const SearchBox = ({ searchHandler }) => {
return (
<Row>
<Col span={12} offset={6}>
<Search
placeholder="Search for movies to schedule!"
enterButton="Search"
size="large"
onSearch={value => searchHandler(value)}
/>
</Col>
</Row>
);
};
const MovieCard = ({
Title,
imdbID,
Poster,
ShowDetails,
DetailRequest,
ActivateModal,
}) => {
const clickHandler = () => {
ActivateModal(true);
DetailRequest(true);
fetch(`http://www.omdbapi.com/?i=${imdbID}&apikey=xxxxxxxx`)
.then(resp => resp)
.then(resp => resp.json())
.then(response => {
DetailRequest(false);
ShowDetails(response);
});
};
return (
<Col style={{ margin: '50px' }} span={3}>
<div>
<Card
style={{ width: 300 }}
cover={
<img
alt={Title}
src={
Poster === 'N/A'
? 'https://placehold.it/198x264&text=Image+Not+Found'
: Poster
}
/>
}
onClick={() => clickHandler()}
>
<Meta title={Title} />
</Card>
</div>
</Col>
);
};
const MovieDetail = ({
Title,
Actors,
Released,
Rated,
Runtime,
Genre,
Poster,
Plot,
}) => {
return (
<Row>
<Col span={11}>
<img
src={
Poster === 'N/A'
? 'https://placehold.it/198x264&text=Image+Not+Found'
: Poster
}
alt={Title}
/>
</Col>
<Col span={13}>
<Row>
<Col>
<TextTitle>{Title}</TextTitle>
</Col>
</Row>
<Row style={{ marginBottom: '.7em' }}>
<Col>{Actors}</Col>
</Row>
<Row style={{ marginBottom: '.7em' }}>
<Col>
<Tag>{Released}</Tag>
<Tag>{Rated}</Tag>
<Tag>{Runtime}</Tag>
<Tag>{Genre}</Tag>
</Col>
</Row>
<Row>
<Col>{Plot}</Col>
</Row>
</Col>
</Row>
);
};
const Loader = () => (
<div>
<Spin />
</div>
);
function Movies() {
const [data, setData] = useState(null);
const [error, setError] = useState(null);
const [query, setQuery] = useState('');
const [activateModal, setActivateModal] = useState(false);
const [details, setShowDetails] = useState(false);
const [detailRequest, setDetailRequest] = useState(false);
useEffect(() => {
setError(null);
setData(null);
fetch(`http://www.omdbapi.com/?s=${query}&apikey=xxxxxxxx`)
.then(resp => resp)
.then(resp => resp.json())
.then(response => {
if (response.Response === 'False') {
setError(response.Error);
} else {
setData(response.Search);
}
})
.catch(({ message }) => {
setError(message);
});
}, [query]);
return (
<div className="Movies">
<Layout className="layout">
<Content>
<div style={{ background: '#4a576e', padding: 60, minHeight: 300 }}>
<SearchBox searchHandler={setQuery} />
<br />
<Row justify="center">
{data !== null &&
data.length > 0 &&
data.map((result, index) => (
<MovieCard
ShowDetails={setShowDetails}
DetailRequest={setDetailRequest}
ActivateModal={setActivateModal}
key={index}
{...result}
/>
))}
</Row>
</div>
<Modal
title="Details"
centered
visible={activateModal}
onCancel={() => setActivateModal(false)}
/* onOk= {() => What do I put here? */
width={800}
footer={[
<Button key="cancel" onClick={() => setActivateModal(false)}>
Cancel
</Button>,
<Button
key="schedule" /* onClick={() => setActivateForm(true)} */
>
Schedule
</Button>,
]}
>
{detailRequest === false ? (
<MovieDetail {...details} />
) : (
<Loader />
)}
</Modal>
</Content>
</Layout>
</div>
);
}
export default Movies;
Assuming all the routes are set up properly in your App.js, add the following changes:
Add this to your import list:
import { Link } from "react-router-dom";
In the Movies function, add the const [activeForm, setActiveForm] = useState(false); as shown below
function Movies() {
const [data, setData] = useState(null);
const [error, setError] = useState(null);
const [query, setQuery] = useState('');
const [activateModal, setActivateModal] = useState(false);
const [details, setShowDetails] = useState(false);
const [detailRequest, setDetailRequest] = useState(false);
const [activateForm, setActivateForm] = useState(false);
In the return for your function, in the div tag right under the "Content" tag, add ActivateForm={setActivateForm} as shown below.
<div style={{ background: '#4a576e', padding: 60, minHeight: 300 }}>
<SearchBox searchHandler={setQuery} />
<br />
<Row justify="center">
{ data !== null && data.length > 0 && data.map((result, index) => (
<MovieCard
ShowDetails={setShowDetails}
DetailRequest={setDetailRequest}
ActivateModal={setActivateModal}
ActivateForm={setActivateForm}
key={index}
{...result}
/>
))}
</Row>
</div>
Finally, in the Modal tag, append to the "onOk" as such, and also in your Modal footer, add the following for "onClick".
<Modal
title='Details'
centered
visible={activateModal}
onCancel={() => setActivateModal(false)}
onOk={() => setActivateForm(true)}
width={800}
footer={[
<Button key="cancel" onClick={() => setActivateModal(false)}>
Cancel
</Button>,
<Button key="schedule" onClick={() =>setActivateForm(true)}><Link to='/ScheduleForm'>Schedule</Link ></Button>
]}
>
{ detailRequest === false ?
(<MovieDetail {...details} />) :
(<Loader />)
}
</Modal>

React - how to invoke popup window in my case?

I'm not a React expert yet thus I have a question for you - how to invoke my popup window from:
import {options, columns,convertToArray} from './consts'
const index = () => {
const {data, loading, error, performFetch} = fetchHook({path: "/xxx/yyy", fetchOnMount: true})
return (
<div className={classes.Container}>
<h1>List of products</h1>
<Divider className={classes.Divider} />
<ProductTable data={convertToArray(data)} options={options} columns={columns}/>
</div>
)
}
export default index;
consts.js
export const actions = (productPropertyId, showModal) => {
const productDetails = (productPropertyId) => {
}
const removeProduct = (productPropertyId, showModal) => {
actions(productPropertyId, showModal);
return (
<div className={classes.actionsContainer}>
<Button
onClick={() => productDetails(productPropertyId)}
> {"More"}
</Button>
<Button
const removeProduct = (productPropertyId, showModal) => {
actions(productPropertyId, showModal);
>{"Remove"}
</Button>
</div>
)
};
export const convertToArray = (productList) => {
let products = []
if (productList != null) {
productList.map(product => {
column1, column2, column3, actions(product.id)]
products.push(prod)
})
}
return products;
};
My popup is --> <FormDialog/> based on react Materials.
Is it possible to invoke popup in this place?
I have a react material table with some columns. The last column contains 2 buttons, one of them is "Remove" (row). Here I want to invoke my popup. Maybe I should rebuild my structure?
UPDATE
Below is my popup - I wonder how to run this popup from the place above:
const formDialog = (popupOpen) => {
const [open, setOpen] = React.useState(false);
const handleClickOpen = () => {
setOpen(true);
};
const handleClose = () => {
setOpen(false);
};
return (
<div>
{/*<Button variant="outlined" color="primary" onClick={handleClickOpen}>*/}
{/* Open alert dialog*/}
{/*</Button>*/}
<Dialog open={open} onClose={handleClose} aria-labelledby="form-dialog-title">
<DialogTitle id="form-dialog-title">Subscribe</DialogTitle>
<DialogContent>
<DialogContentText>
To subscribe to this website, please enter your email address here. We will send updates
occasionally.
</DialogContentText>
<TextField
autoFocus
margin="dense"
id="name"
label="Email Address"
type="email"
fullWidth
/>
</DialogContent>
<DialogActions>
<Button onClick={handleClose} color="primary">
Cancel
</Button>
<Button onClick={handleClose} color="primary">
Subscribe
</Button>
</DialogActions>
</Dialog>
</div>
);
}
export default formDialog;
UPDATE 2
I updated my code taking into cosideration the tips from your response, see above. Can I add a parameter showModal in my export const actions = (productPropertyId, showModal) and then invoke this component with different showModal value? UNfortunately my popup doesn't appear when I click on Remove button :(
You can invoke it conditionally and controle it using some state variable. Like this:
const [removeModal, removeToggle] = useState(false);
return (<>
<div className={classes.actionsContainer}>
<Button
onClick={() => productDetails(productPropertyId)}
> {"More"}
</Button>
<Button
onClick={() => removeToggle(true)}
>{"Remove"}
</Button>
</div>
{removeModal ? <YourComponent /> : ''}
</>
)
I'm using a react fragment there <></> just to position the modal div outside the main div, but you can also invoke it inside your main div as well (I usually do this and set the position: fixed so the modal/popup coud appear in top of everything).

Resources