a problem with the shopping cart button in react - javascript

I'm trying to make a button where every time I click it adds the item to the cart, but the problem is that when I click nothing happens, as if it were not even a button:
Product.js :
import React from 'react'
import './Product.css'
import {useStateValue} from './StateProvider'
function Products({id,title,image,price,rating}) {
const [state,dispatch] = useStateValue();
const addToBasket = () => {
dispatch({
type: 'ADD_TO_BASKET',
item:{
id: id,
title: title,
image: image,
price: price,
rating: rating,
},
});
};
return (
<div className="product">
<div className="product_info">
<p>{title}</p>
<p className="product_price">
<small>$</small>
<strong>{price}</strong>
</p>
<div className="product_rating">
{Array(rating).fill().map((_,i) => (
<p>⭐</p>
))}
</div>
</div>
<img src={image} alt="" />
<button onClick={addToBasket}>Add to Basket</button>
</div>
);
}
export default Products;
Reducer.js :
export const initialState ={
basket:[],
};
const reducer =(state,action)=>{
console.log(action);
switch(action.type){
case "ADD_TO_BASKET":
return {
...state,
basket:[...state.basket,action.item],
};
default:
return state;
}
};
export default reducer;
Index.js :
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { StateProvider } from './StateProvider';
import reducer, {initialState} from './reducer'
ReactDOM.render(
<React.StrictMode>
<StateProvider initialState={initialState} reducer={reducer}>
<App />
</StateProvider>
</React.StrictMode>,
document.getElementById('root')
);
reportWebVitals();
Header.js (where I put the basket logo):
import React from 'react';
import './Header.css';
import SearchIcon from '#material-ui/icons/Search'
import ShopppingBasketIcon from '#material-ui/icons/ShoppingBasket'
import {Link} from 'react-router-dom'
import { useStateValue } from "./StateProvider"
function Header() {
const [{basket},dispatch] = useStateValue();
return (
<div className="header">
<Link to="/">
<img className="header__logo" src="http://pngimg.com/uploads/amazon/amazon_PNG11.png"/>
</Link>
<div className="header__search">
<input className="header__searchInput" type="text"/>
<SearchIcon className="header__searchIcon"/>
</div>
<div className="header__nav">
<Link to="/checkout">
<div className="header__optionBasket">
<ShopppingBasketIcon/>
<span className="header__optionLineTwo
header__basketCount">{basket?.lenght}</span>
</div>
</Link>
</div>
</div>
)
}
export default Header
therefore, where I find the problem is that when I click "add to cart" it does not click anything, as if the button did not exist and does not take any action..

try preventing default behaviour like so
const addToBasket = (e) => {
e.preventDefault();
dispatch({
type: 'ADD_TO_BASKET',
item:{
id: id,
title: title,
image: image,
price: price,
rating: rating,
},
});
};
and you can also try setting a type on the button
<button type="button" onClick={addToBasket}>Add to Basket</button>

Related

Provider tag in react causing blank screen

I am trying to make a webpage using React js and use redux template. I am trying to wrap my component around < Provider >. After wrapping i get a blank page. I tried using React developer tools that too appears blank. here is my code.Here is the error i am getting
Uncaught Error: Expected the reducer to be a function.
at createStore (createStore.js:55:1)
at ./src/index.js (index.js:9:1)
at options.factory (react refresh:6:1)
at __webpack_require__ (bootstrap:24:1)
at startup:7:1
at startup:7:1
Main.js
import Title from './Title'
import Photowall from './Photowall'
import AddPhoto from './AddPhoto'
import { Route } from 'react-router-dom'
class Main extends Component{
constructor(){
super()
this.state= {
posts : [{
id: "0",
description: "beautiful landscape",
imageLink: "https://image.jimcdn.com/app/cms/image/transf/none/path/sa6549607c78f5c11/image/i4eeacaa2dbf12d6d/version/1490299332/most-beautiful-landscapes-in-europe-lofoten-european-best-destinations-copyright-iakov-kalinin.jpg" +
"3919321_1443393332_n.jpg"
}, {
id: "1",
description: "Aliens???",
imageLink: "https://s3.india.com/wp-content/uploads/2017/12/rocket.jpg"
}, {
id: "2",
description: "On a vacation!",
imageLink: "https://fm.cnbc.com/applications/cnbc.com/resources/img/editorial/2017/08/24/104670887-VacationExplainsTHUMBWEB.1910x1000.jpg"
}],
}
this.removePhoto=this.removePhoto.bind(this)
}
removePhoto(postRemoved){
console.log(postRemoved.description)
this.setState((state) => ({
posts: state.posts.filter(post => post !== postRemoved)
}))
}
addPhoto(postSubmitted){
this.setState(state => ({
posts:state.posts.concat([postSubmitted])
}))
}
componentDidMount(){
}
componentDidUpdate(prevProps,prevState){
console.log(prevState.posts)
console.log(this.state)
}
render() {
return (
<div>
<Route exact path="/" render={() => (
<div>
<Title title={'Photowall'}/>
<Photowall posts={this.state.posts} onRemovePhoto={this.removePhoto} onNavigate={this.navigate}/>
</div>
)}/>
<Route path="/AddPhoto" render={({history})=>(
<AddPhoto onAddPhoto={(addedPost)=>{
this.addPhoto(addedPost)
history.push('/')
}}/>
)}/>
</div>
)
}
}
export default Main
AddPhoto.js
import React, { Component } from "react"
class AddPhoto extends Component{
constructor(){
super()
this.handleSubmit=this.handleSubmit.bind(this)
}
handleSubmit(event){
event.preventDefault();
const imageLink = event.target.elements.link.value
const description = event.target.elements.description.value
const post = {
id:0,
description:description,
imageLink:imageLink
}
if(description && imageLink){
this.props.onAddPhoto(post)
}
}
render(){
return(
<div>
<h1>Photowall</h1>
<div className="form">
<form onSubmit={this.handleSubmit}>
<input type="text" placeholder="Link" name="link"/>
<input type="text" placeholder="Description" name="description"/>
<button>Post</button>
</form>
</div>
</div>
)
}
}
export default AddPhoto
Photo.js
import React, {Component} from "react";
import PropTypes from 'prop-types'
function Photo(props){
const post =props.post
return <figure className="figure">
<img className="photo" src={post.imageLink} alt={post.description}/>
<figcaption><p>{post.description}</p></figcaption>
<div className="button-container">
<button className="remove-button" onClick={()=>{
props.onRemovePhoto(post);
}}> Remove </button>
</div>
</figure>
}
Photo.propTypes={
post: PropTypes.object.isRequired,
onRemovePhoto:PropTypes.func.isRequired
}
export default Photo
Photowall.js
import React,{ Component} from 'react'
import Photo from './Photo'
import PropTypes from 'prop-types'
import {Link} from 'react-router-dom'
function Photowall(props){
return <div>
<Link className='addIcon' to='/AddPhoto' ><img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTIgMGMtNi42MjcgMC0xMiA1LjM3My0xMiAxMnM1LjM3MyAxMiAxMiAxMiAxMi01LjM3MyAxMi0xMi01LjM3My0xMi0xMi0xMnptNyAxNGgtNXY1aC00di01aC01di00aDV2LTVoNHY1aDV2NHoiLz48L3N2Zz4="></img> </Link>
{/*<button onClick={props.onNavigate} className='addIcon'> + </button>*/}
<div className='photo-grid'>
{props.posts.map((post, index) => <Photo key={index} post={post} onRemovePhoto={props.onRemovePhoto}/>)}
</div>
</div>
}
Photowall.propTypes={
posts: PropTypes.array.isRequired,
onRemovePhoto:PropTypes.func.isRequired
}
export default Photowall
index.js
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import Main from './Components/Main'
import './styles/stylesheet.css'
import {BrowserRouter} from 'react-router-dom'
import {createStore} from 'redux'
import rootReducer from './redux/reducer'
import {Provider} from "react-redux";
const store = createStore(rootReducer)
ReactDOM.render(<Provider store={store}><BrowserRouter><Main/></BrowserRouter></Provider>, document.getElementById('root'));
reducer.js
import posts from '../data/posts'
const postReducer = function posts(state = posts,action){
return state
}
export default postReducer

Compose button is not working in the file and i have file in mail Slice for opening the pop up to compose

I am using redux for creating data layer and logic is given below as my code is but the compose button is not working properly it should open a pop up to compose mail. I have imported all the necessary icons and have imported all the buttons, i am using redux form for the data input and firebase for real time database, MailSlice file is very well written but if required, will send it.
Sidebar File
import React from 'react';
import './Sidebar.css';
import {Button, IconButton} from "#mui/material";
import AddIcon from '#mui/icons-material/Add';
import InboxIcon from '#mui/icons-material/Inbox';
import SidebarOption from './SidebarOption';
import StarIcon from '#mui/icons-material/Star';
import AccessTimeIcon from '#mui/icons-material/AccessTime';
import LabelImportantIcon from '#mui/icons-material/LabelImportant';
import NearMeIcon from '#mui/icons-material/NearMe';
import NoteIcon from '#mui/icons-material/Note';
import ExpandMoreIcon from '#mui/icons-material/ExpandMore';
import PersonIcon from '#mui/icons-material/Person';
import DuoIcon from '#mui/icons-material/Duo';
import PhoneIcon from '#mui/icons-material/Phone';
import { useDispatch } from 'react-redux';
import { openSendMessage } from './features/mailSlice';
function Sidebar() {
const dispatch = useDispatch();
return (
<div className="sidebar">
<Button
startIcon={<AddIcon fontSize= "large" />}
className="sidebar__compose"
onClick={() => dispatch(openSendMessage())}
>
Compose
</Button>
<SidebarOption Icon={InboxIcon} title = "Inbox" number={54} selected = {true}/>
<SidebarOption Icon={StarIcon} title = "Starred" number={14} />
<SidebarOption Icon={AccessTimeIcon} title = "Snoozed" number={24} />
<SidebarOption Icon={LabelImportantIcon} title = "Important" number={34} />
<SidebarOption Icon={NearMeIcon} title = "Sent" number={21} />
<SidebarOption Icon={NoteIcon} title = "Drafts" number={4} />
<SidebarOption Icon={ExpandMoreIcon} title = "More" number={39}/>
<div className='sidebar__footer'>
<div className='sidebar__footerIcons'>
<IconButton>
<PersonIcon/>
</IconButton>
<IconButton>
<DuoIcon/>
</IconButton>
<IconButton>
<PhoneIcon/>
</IconButton>
</div>
</div>
</div>
);
}
export default Sidebar;
SendMail File
import { Button } from '#mui/material';
import React from 'react'
import "./SendMail.css";
import CloseIcon from '#mui/icons-material/Close';
import {useForm} from "react-hook-form";
import { useDispatch } from 'react-redux';
import { closeSendMessage } from './features/mailSlice';
import {db} from "./Firebase";
import firebase from "firebase/compat/app";
import "firebase/compat/auth";
import "firebase/compat/firestore";
function SendMail() {
const {register, handleSubmit, watch, errors} = useForm();
const dispatch = useDispatch();
const onSubmit = (formData) => {
console.log(formData);
db.collection("emails").add({
to: formData.to,
subject: formData.subject,
message: formData.message,
timestamp: firebase.firestore.FieldValue.serverTimestamp(),
});
dispatch(closeSendMessage());
};
return (
<div className='sendMail'>
<div className='sendMail__header'>
<h3>New Message</h3>
<CloseIcon onClick={() => dispatch(closeSendMessage())} className='sendMail__close'/>
</div>
<form onSubmit={handleSubmit(onSubmit)}>
<input name='to'
placeholder='To:'
type="email"
ref={register ({required: true})}
/>
{errors.to && (<p className='sendMail__error'>Required field</p>)}
<input name='subject'
placeholder='Subject'
type="text"
ref={register ({required: true})}
/>
{errors.subject && (<p className='sendMail__error'>Required field</p>)}
<input name='message'
placeholder='Message...'
type="text"
className='sendMail__message'
ref={register ({required: true})}
/>
{errors.message && (<p className='sendMail__error'>Required field</p>)}
<div className='sendMail__options'>
<Button className='sendMail__send'
variant='contained'
color='primary'
type='submit'
>
Send
</Button>
</div>
</form>
</div>
)
}
export default SendMail;

Blank screen after using react <Provider>

I am trying to make a webpage using React js and use redux template. I am trying to wrap my component around < Provider >. After wrapping i get a blank page. I tried using React developer tools that too appears blank. here is my code. I have tried different methods nut none of them works.
Main.js
import Title from './Title'
import Photowall from './Photowall'
import AddPhoto from './AddPhoto'
import { Route } from 'react-router-dom'
class Main extends Component{
constructor(){
super()
this.state= {
posts : [{
id: "0",
description: "beautiful landscape",
imageLink: "https://image.jimcdn.com/app/cms/image/transf/none/path/sa6549607c78f5c11/image/i4eeacaa2dbf12d6d/version/1490299332/most-beautiful-landscapes-in-europe-lofoten-european-best-destinations-copyright-iakov-kalinin.jpg" +
"3919321_1443393332_n.jpg"
}, {
id: "1",
description: "Aliens???",
imageLink: "https://s3.india.com/wp-content/uploads/2017/12/rocket.jpg"
}, {
id: "2",
description: "On a vacation!",
imageLink: "https://fm.cnbc.com/applications/cnbc.com/resources/img/editorial/2017/08/24/104670887-VacationExplainsTHUMBWEB.1910x1000.jpg"
}],
}
this.removePhoto=this.removePhoto.bind(this)
}
removePhoto(postRemoved){
console.log(postRemoved.description)
this.setState((state) => ({
posts: state.posts.filter(post => post !== postRemoved)
}))
}
addPhoto(postSubmitted){
this.setState(state => ({
posts:state.posts.concat([postSubmitted])
}))
}
componentDidMount(){
}
componentDidUpdate(prevProps,prevState){
console.log(prevState.posts)
console.log(this.state)
}
render() {
return (
<div>
<Route exact path="/" render={() => (
<div>
<Title title={'Photowall'}/>
<Photowall posts={this.state.posts} onRemovePhoto={this.removePhoto} onNavigate={this.navigate}/>
</div>
)}/>
<Route path="/AddPhoto" render={({history})=>(
<AddPhoto onAddPhoto={(addedPost)=>{
this.addPhoto(addedPost)
history.push('/')
}}/>
)}/>
</div>
)
}
}
export default Main
AddPhoto.js
import React, { Component } from "react"
class AddPhoto extends Component{
constructor(){
super()
this.handleSubmit=this.handleSubmit.bind(this)
}
handleSubmit(event){
event.preventDefault();
const imageLink = event.target.elements.link.value
const description = event.target.elements.description.value
const post = {
id:0,
description:description,
imageLink:imageLink
}
if(description && imageLink){
this.props.onAddPhoto(post)
}
}
render(){
return(
<div>
<h1>Photowall</h1>
<div className="form">
<form onSubmit={this.handleSubmit}>
<input type="text" placeholder="Link" name="link"/>
<input type="text" placeholder="Description" name="description"/>
<button>Post</button>
</form>
</div>
</div>
)
}
}
export default AddPhoto
Photo.js
import React, {Component} from "react";
import PropTypes from 'prop-types'
function Photo(props){
const post =props.post
return <figure className="figure">
<img className="photo" src={post.imageLink} alt={post.description}/>
<figcaption><p>{post.description}</p></figcaption>
<div className="button-container">
<button className="remove-button" onClick={()=>{
props.onRemovePhoto(post);
}}> Remove </button>
</div>
</figure>
}
Photo.propTypes={
post: PropTypes.object.isRequired,
onRemovePhoto:PropTypes.func.isRequired
}
export default Photo
Photowall.js
import React,{ Component} from 'react'
import Photo from './Photo'
import PropTypes from 'prop-types'
import {Link} from 'react-router-dom'
function Photowall(props){
return <div>
<Link className='addIcon' to='/AddPhoto' ><img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTIgMGMtNi42MjcgMC0xMiA1LjM3My0xMiAxMnM1LjM3MyAxMiAxMiAxMiAxMi01LjM3MyAxMi0xMi01LjM3My0xMi0xMi0xMnptNyAxNGgtNXY1aC00di01aC01di00aDV2LTVoNHY1aDV2NHoiLz48L3N2Zz4="></img> </Link>
{/*<button onClick={props.onNavigate} className='addIcon'> + </button>*/}
<div className='photo-grid'>
{props.posts.map((post, index) => <Photo key={index} post={post} onRemovePhoto={props.onRemovePhoto}/>)}
</div>
</div>
}
Photowall.propTypes={
posts: PropTypes.array.isRequired,
onRemovePhoto:PropTypes.func.isRequired
}
export default Photowall
index.js
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import Main from './Components/Main'
import './styles/stylesheet.css'
import {BrowserRouter} from 'react-router-dom'
import {createStore} from 'redux'
import rootReducer from './redux/reducer'
import {Provider} from "react-redux";
const store = createStore(rootReducer)
ReactDOM.render(<Provider store={store}><BrowserRouter><Main/></BrowserRouter></Provider>, document.getElementById('root'));
reducer.js
import posts from '../data/posts'
const postReducer = function posts(state = posts,action){
return state
}
export default postReducer

Error: could not find react-redux context value; please ensure the component is wrapped in a <Provider>

Please I'm new to react. I'm trying to render data from my backend using react axios and hooks. I keep on getting this error message and I ensured the App was wrapped in a provider. Do I have to wrap the Homescreen component in a provider before exporting it? Thanks.
This is the Homescreen.js ; To display the data
import React, { useEffect} from 'react';
import {Link} from 'react-router-dom'
import { useSelector } from 'react-redux/lib/hooks/useSelector';
import { useDispatch } from 'react-redux/lib/hooks/useDispatch';
import { listProducts } from '../actions/productActions';
import {Provider }from 'react-redux';
function HomeScreen (props) {
const productList = useSelector(state => state.productList);
const { products, loading, error} = productList;
const dispatch = useDispatch();
useEffect(()=>{
dispatch(listProducts());
return ()=> {
//
};
}, [ dispatch ])
return loading? <div> loading... </div>:
error? <div> {error} </div>:
(
<ul className="products">
{
products.map(product =>
<li key = {product._id} >
<div className="product">
<Link to= {'/product/'+ product._id}>
<img src={product.image} className="product-image" alt="product"></img>
</Link>
<div className="product-name">
<Link to= {'/product/'+ product._id}> {product.name} </Link>
</div>
<div className="product-brand"> {product.brand}</div>
<div className="product-price"> ${product.price}</div>
<div className="rating"> {product.price} Stars ({product.numReviews} Reviews)</div>
</div>
</li>
)
}
</ul>
)
}
export default HomeScreen;
This is the App;
import React from 'react';
import {Link, BrowserRouter ,Route } from 'react-router-dom'
import './App.css';
import HomeScreen from './screens/HomeScreen'
import ProductScreen from './screens/ProductScreen'
import {Provider }from 'react-redux';
function App() {
const openMenu = ()=>{
document.querySelector(".sidebar").classList.add("open")
}
const closeMenu = ()=>{
document.querySelector(".sidebar").classList.remove("open")
}
return (
<BrowserRouter>
<div className="grid-container">
<header className="header">
<div className="brand">
<button onClick={openMenu}>
☰
</button>
<Link to = "/">Amazone</Link>
</div>
<div className="header-links">
Cart
SigniN
</div>
</header>
<aside className="sidebar">
<h3> Shopping Categories</h3>
<button className="sidebar-close-button" onClick={closeMenu}>X </button>
<li>
Pants
</li>
<li>
Shirts
</li>
</aside>
<main className="main">
<div className="content">
<Route path="/product/:id" component = {ProductScreen} />
<Route path="/" exact = {true} component = {HomeScreen} />
</div>
</main>
<footer className="footer">
All Rights Reserved
</footer>
</div>
</BrowserRouter>
);
}
export default App;
This is the Index.js
import React from 'react';
import {Provider }from 'react-redux';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import allreducer from './allreducer.js'
import thunk from 'redux-thunk';
import {createStore, applyMiddleware, compose} from 'redux';
// to see the action dispatched in the state at the browser
const composeEnhancer = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const initialState = {};
//Thunk is a middleware that allows operation of async in the action
const store = createStore(allreducer, initialState, composeEnhancer(applyMiddleware(thunk)));
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>
,
document.getElementById('root')
);
serviceWorker.unregister();
The Reducer:
import { PRODUCT_LIST_REQUEST, PRODUCT_LIST_SUCCESS, PRODUCT_LIST_FAIL, PRODUCT_DETAILS_REQUEST, PRODUCT_DETAILS_SUCCESS, PRODUCT_DETAILS_FAIL } from "../constants/productConstants";
//Reducers
function productListReducer (state = {product: []}, action){
switch(action.type){
case PRODUCT_LIST_REQUEST:
return {loading: true};
case PRODUCT_LIST_SUCCESS:
return {loading: false, products: action.payload}
case PRODUCT_LIST_FAIL:
return {loading:false, error: action.payload}
default:
return state;
}
}
Reducer Constants;
export const PRODUCT_LIST_REQUEST = 'PRODUCT_LIST_REQUEST';
export const PRODUCT_LIST_SUCCESS = 'PRODUCT_LIST_SUCCESS';
export const PRODUCT_LIST_FAIL = 'PRODUCT_LIST_FAIL';
export const PRODUCT_DETAILS_REQUEST = 'PRODUCT_DETAILS_REQUEST';
export const PRODUCT_DETAILS_SUCCESS = 'PRODUCT_DETAILS_SUCCESS';
export const PRODUCT_DETAILS_FAIL = 'PRODUCT_DETAILS_FAIL';
Reducer Action;
import { PRODUCT_LIST_REQUEST, PRODUCT_LIST_SUCCESS, PRODUCT_LIST_FAIL, PRODUCT_DETAILS_REQUEST, PRODUCT_DETAILS_SUCCESS, PRODUCT_DETAILS_FAIL } from "../constants/productConstants";
//Reducers
function productListReducer (state = {product: []}, action){
switch(action.type){
case PRODUCT_LIST_REQUEST:
return {loading: true};
case PRODUCT_LIST_SUCCESS:
return {loading: false, products: action.payload}
case PRODUCT_LIST_FAIL:
return {loading:false, error: action.payload}
default:
return state;
}
}
The issue is that you're importing your hooks from 'react-redux/lib/hooks/useSelector' instead of 'react-redux'.
Instead of:
import { useSelector } from 'react-redux/lib/hooks/useSelector';
import { useDispatch } from 'react-redux/lib/hooks/useDispatch';
use:
import { useSelector } from 'react-redux';
import { useDispatch } from 'react-redux';

react-pdf - Error: Target container is not a DOM element

I am using React with react-pdf and trying to render a PDF into my modal. However, my modal gets loaded on a button click, so it's not loaded on app load. But it is trying to call the PDF rendering call on app load and thus generating the error: 'Error: Target container is not a DOM element'. I'm not sure of how to fix this issue.
Here is my entire modal component:
import ReactModal from 'react-modal';
import React, { useEffect, useRef } from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import ReactPDF, { PDFViewer } from '#react-pdf/renderer';
import CloseButton from './CloseButton';
import MessageHub from '../message/MessageHub';
import PDFPlacard from '../placards/PDFPlacard';
const PDF = () => (
<PDFViewer>
<PDFPlacard />
</PDFViewer>
);
const PlacardsModal = (props) => {
const { openPlacards, setOpenPlacards, customStyles } = props;
const numPlacards = React.createRef();
const ref = useRef(null);
// this call needs to happen after the modal and #PDFPlacard is rendered
ReactDOM.render(<PDF />, document.getElementById('PDFPlacard'));
const handleSubmit = (evt) => {
evt.preventDefault();
if (numPlacards.current.value === '') {
ref.current('Please fill in the number of placards.');
} else {
// submit form
}
};
return (
<ReactModal
isOpen={openPlacards}
style={customStyles}
className={'print-placards-modal'}
closeTimeoutMS={1000}
>
<CloseButton setOpenModal={setOpenPlacards} />
<h2>Print Placards</h2>
{/* eslint-disable-next-line react/no-children-prop */}
<MessageHub children={(add) => (ref.current = add)} />
<form className={'form'} onSubmit={handleSubmit}>
<div className={'form-group row'}>
<label
htmlFor={'numPlacards'}
className={'col-sm-6 col-form-label'}
>
Number of Placards:
</label>
<div className={'col-sm-6'}>
<input
id={'numPlacards'}
type={'number'}
className={'form-control'}
ref={numPlacards}
/>
</div>
</div>
<button
className={'btn btn-primary d-block mx-auto mb-2'}
type={'submit'}
value={'Print'}
/>
</form>
<div id={'PDFPlacard'} />
</ReactModal>
);
};
PlacardsModal.propTypes = {
openPlacards: PropTypes.bool,
setOpenPlacards: PropTypes.func,
customStyles: PropTypes.object,
title: PropTypes.string
};
export default PlacardsModal;
Here is PDFPlacard.js:
import React from 'react';
import {
Page,
Text,
View,
Document,
StyleSheet
} from '#react-pdf/renderer';
// Create styles
const styles = StyleSheet.create({
page: {
flexDirection: 'row',
backgroundColor: '#E4E4E4'
},
section: {
margin: 10,
padding: 10,
flexGrow: 1
}
});
// Create Document Component
const PDFPlacard = (type) => (
<Document>
<Page size="letter" style={styles.page}>
<View style={styles.section}>
<Text>Section #1</Text>
</View>
<View style={styles.section}>
<Text>Section #2</Text>
</View>
</Page>
</Document>
);
export default PDFPlacard;
And my index.js:
import React from 'react';
import { render } from 'react-dom';
import 'bootstrap/dist/css/bootstrap.min.css';
import 'bootstrap/dist/js/bootstrap.min';
import './index.css';
import App from './App';
const title = 'title';
render(<App title={title} />, document.getElementById('root'));
// eslint-disable-next-line no-undef
module.hot.accept();
The parent is loading the PlacardsModal like this:
...
<button
className={'btn btn-info mb-3'}
onClick={() => setOpenPlacards(true)}
>
Placards
</button>
...
<PlacardsModal
openPlacards={openPlacards}
setOpenPlacards={setOpenPlacards}
customStyles={customStyles}
/>
Finally got the answer from another source. I should not have been making that ReactDOM.render( call at all. I should just have been including the PDF components on my page.
Like this:
...
<button
className={'btn btn-primary d-block mx-auto mb-2'}
type={'submit'}
value={'Print'}
/>
</form>
<!-- not this -->
<div id={'PDFPlacard'} />
<!-- this -->
<PDF />
</ReactModal>
);
};
...

Categories

Resources