Sorry, React developer newbie. I have a working React Class Component with a popup Modal. It displays when you click on a Item Card:
import React from 'react';
import {
Card, Button, CardImg, CardTitle, CardText, CardGroup,
CardSubtitle, CardBody, CardFooter, CardHeader, CardColumns, CardDeck
} from 'reactstrap';
import Config from 'config';
import { decompressToBase64, formatter } from './common.js'
import "./Item.css";
import Modal from 'react-modal';
const customStyles = {
content: {
top: '50%',
left: '50%',
right: 'auto',
bottom: 'auto',
marginRight: '-50%',
transform: 'translate(-50%, -50%)',
},
};
Modal.setAppElement('#root');
class FeaturedCards extends React.Component {
constructor() {
super();
this.state = {
name: 'React',
apiData: [],
isOpen: false
};
}
async componentDidMount() {
const tokenString = sessionStorage.getItem("token");
const token = JSON.parse(tokenString);
let headers = new Headers({
"Accept": "application/json",
"Content-Type": "application/json",
'Authorization': 'Bearer ' + token.token
});
const response = await fetch(Config.apiUrl + `/api/Items/GetFeaturedItems`, {
method: "GET",
headers: headers
});
const json = await response.json();
console.log(json);
this.setState({ itemList: json });
}
render() {
const items = this.state.itemList;
let subtitle;
handleClick = handleClick.bind(this);
closeModal = closeModal.bind(this);
function handleClick() {
this.setState({ isOpen: true });
}
function closeModal() {
console.log('Clicked close button')
this.setState({ isOpen: false });
}
function afterOpenModal() {
// references are now sync'd and can be accessed.
subtitle.style.color = '#f00';
}
return (
<div>
<CardGroup className="card-group-scroll">
{items && items.map(item =>
<>
<Card key={item.itemNumber} tag="a" onClick={() => handleClick()} style={{ cursor: "pointer" }}>
<CardHeader tag="h3">Featured</CardHeader>
<CardImg top className="card-picture" src={"data:image/png;base64," + decompressToBase64(item.images[0]?.compressedImageData)} id={item.itemNumber + "Img"} alt={item.itemNumber} />
<CardBody className="card-body">
<CardTitle tag="h5">{item.itemNumber}</CardTitle>
<CardSubtitle tag="h6" className="mb-2 text-muted">{item.categoryName}</CardSubtitle>
<CardText className="card-description">{item.itemDescription}</CardText>
</CardBody>
<CardFooter className="text-muted">{formatter.format(item.price)}</CardFooter>
</Card>
<Modal
isOpen={this.state.isOpen}
onAfterOpen={afterOpenModal}
onRequestClose={() => closeModal()}
style={customStyles}
contentLabel={item.itemNumber}>
<h2 ref={(_subtitle) => (subtitle = _subtitle)}>Hello</h2>
<button onClick={() => closeModal()}>close</button>
<div>I am a modal</div>
<form>
<input />
<button>tab navigation</button>
<button>stays</button>
<button>inside</button>
<button>the modal</button>
</form>
</Modal>
</>
)}
</CardGroup>
</div>
);
}
}
export default FeaturedCards;
I need to use this same modal in several different places. I need the modal to have access to the item I clicked on. How do I refactor the modal into a separate file?
Any help would be appreciated.
UPDATE
My first attempt:
import React from 'react';
import "./Item.css";
import Modal from 'react-modal';
const customStyles = {
content: {
top: '50%',
left: '50%',
right: 'auto',
bottom: 'auto',
marginRight: '-50%',
transform: 'translate(-50%, -50%)',
},
};
Modal.setAppElement('#root');
class ItemModal extends React.Component {
constructor(props) {
super(props);
}
render() {
let subtitle;
closeModal = closeModal.bind(this);
function closeModal() {
console.log('Clicked close button')
this.setState({ isOpen: false });
}
function afterOpenModal() {
// references are now sync'd and can be accessed.
subtitle.style.color = '#f00';
}
return (
<Modal
isOpen={this.state.isOpen}
onAfterOpen={afterOpenModal}
onRequestClose={() => closeModal()}
style={customStyles}
contentLabel={this.props.item.itemNumber}>
<h2 ref={(_subtitle) => (subtitle = _subtitle)}>Hello</h2>
<button onClick={() => closeModal()}>close</button>
<div>I am a modal</div>
<form>
<input />
<button>tab navigation</button>
<button>stays</button>
<button>inside</button>
<button>the modal</button>
</form>
</Modal>
);
}
}
export default ItemModal;
I call it from FeaturedCards
like this <ItemModal item = { item } />
I get an error: TypeError: this.state is null
. I can't seem to figure out how to read(Share) the state from FeaturedCards
...
Here is the very basic(with only open and close functionalities) example of how you can create a common modal (there could be other ways...).
class ItemModal extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<Modal
isOpen
onRequestClose={this.props.onRequestClose}
>
Sample content
</Modal>
);
}
}
export default ItemModal;
and this can be used like below.
class FeaturedCards extends React.Component {
constructor(props) {
super(props);
this.state = {
isOpen: false
};
}
onRequestClose = () => {
this.setState({isOpen: false});
}
handleClick = () => {
this.setState({ isOpen: true });
}
render() {
const { isOpen } = this.state;
return (
<div>
<button type="button" onClick={this.handleClick}> open Modal</button>
{ isOpen ? <ItemModal onRequestClose={this.onRequestClose} /> : null }
</div>
);
}
}
export default FeaturedCards;