react-to-pdf between two components - javascript

So I am using react-to-pdf to print Html tags to PDF the button is on one component and text is on another, I don't seem to have much knowledge as to how to make the button print index.js as pdf. I am pretty sure that something is wrong in ref and imports
button.js
import React, { Component } from "react";
import Pdf from "react-to-pdf";
const ref = React.createRef();
class Button extends Component {
render() {
return (
<React.Fragment>
<Pdf targetRef={ref} filename="code-example.pdf">
{({ toPdf }) => <button onClick={toPdf}>Generate Pdf</button>}
</Pdf>
</React.Fragment>
);
}
}
export default Button;
index.js
import React, { Component } from "react";
import "./styles.css";
import Button from "./button";
const ref = React.createRef();
class Index extends Component {
render() {
return (
<React.Fragment>
<div className="App">
<div ref={ref}>
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
</div>
</div>
</React.Fragment>
);
}
}
export default Index;
ReactDOM.render(<Button />, document.getElementById("top"));
const rootElement = document.getElementById("root");
ReactDOM.render(<Index />, rootElement);

Use like this:
import React from "react";
import ReactDOM from "react-dom";
import Pdf from "react-to-pdf";
const Button = React.forwardRef((props, ref) => {
return (
<React.Fragment>
<Pdf targetRef={ref} filename="code-example.pdf">
{({ toPdf }) => <button onClick={toPdf}>Generate Pdf</button>}
</Pdf>
</React.Fragment>
);
});
const App = () => {
let docToPrint = React.createRef();
return (
<div>
<div>
<Button ref={docToPrint} />
</div>
<React.Fragment>
<div className="App">
<div
ref={docToPrint}
style={{
borderRadius: "5px",
width: "600px",
height: "400px",
margin: "0 auto",
padding: "10mm"
}}
>
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
</div>
</div>
</React.Fragment>
</div>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Answer output: HERE

You can expose out props from the button to pass in the ref to the component you want saved to PDF. Here's a demo of a PDF button with targetRef and fileName props.
PDFButton.jsx
import React from "react";
import PropTypes from "prop-types";
import Pdf from "react-to-pdf";
// expose a targetRef prop and filename
const PDFButton = ({ children, filename, targetRef }) => (
<Pdf targetRef={targetRef} filename={filename}>
{({ toPdf }) => <button onClick={toPdf}>{children}</button>}
</Pdf>
);
PDFButton.propTypes = {
filename: PropTypes.string,
targetRef: PropTypes.any
};
PDFButton.defaultProps = {
filename: "code-example.pdf"
};
export default PDFButton;
App.js
import React, { createRef } from "react";
import PDFButton from "./PDFButton";
import "./styles.css";
export default function App() {
const pdfRef = createRef(); // create a single ref to pass to button
return (
<div ref={pdfRef} className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<p>This is a demo how to create a save to PDF button</p>
<PDFButton
fileName="awesomePDFButtonDemo.pdf"
targetRef={pdfRef}
>
Save to PDF!
</PDFButton>
</div>
);
}

Related

React 17 Warning: Did not expect server HTML to contain a <a> in <div>

I have read through the existing solutions and still cant seem to get it to work.
components/NavBar.tsx
import { Box, Link } from "#chakra-ui/react";
import { FunctionComponent } from "react";
import NextLink from "next/link";
interface NavBarProps {}
const NavBar: FunctionComponent<any> = (props) => {
return (
<Box {...props} bg="tomato" w="100%" p={4} ml={"auto"} color="white">
<NextLink href="/login">
<Link mr={4}>Login</Link>
</NextLink>
<NextLink href="/register">
<Link>Register</Link>
</NextLink>
</Box>
);
};
export default NavBar;
index.tsx
import NavBar from "../components/navbar";
const Index = () => (
<>
<NavBar></NavBar>
<div>hello world</div>
</>
);
export default Index;
Error Screenshot
Error Messsage
Try
<NavBar/>
instead of
<NavBar></NavBar>

Can't render my component, Expected an assignment or function call and instead saw an expression in React

I written my code following a udemy course. I'm unable to render the Layout component's content is there anything I missed or any syntax mistakes that needs to be corrected to sort this out ?
const Aux = (props) => {props.children}
export default Aux;
import React,{Component} from 'react'
import Layout from './components/Layout/Layout';
class App extends Component
{
render() {
return (
<div>
<Layout>
<p>Hai.. Is this working ? </p>
</Layout>
</div>
);
}
}
export default App;
import React from 'react';
import Aux from '../../hoc/Auxx';
const layout = (props) =>(
<Aux>
<div>Toolbar,Sidebar,Backdrop</div>
<main>
{props.children}
</main>
</Aux>
);
export default layout;
You problem is that Aux is a blank component.
When you use the syntax const Aux = (props) => {props.children} you actually return nothing!
You see, javascript thinks that { } is the function itself and not return your props.children. Just remove the brackets:
const Aux = (props) => props.children;
I've modified your code as below:
const Aux = (props) => props.children // removed the {} so that it can return the children
export default Aux;
import React,{Component} from 'react'
import Layout from './components/Layout/Layout';
class App extends Component
{
render() {
return (
<div>
<Layout>
<p>Hai.. Is this working ? </p>
</Layout>
</div>
);
}
}
export default App;
import React from 'react';
import Aux from '../../hoc/Auxx';
const Layout = (props) =>( //changed the layout to Layout: it needs to be capitalized
<Aux>
<div>Toolbar,Sidebar,Backdrop</div>
<main>
{props.children}
</main>
</Aux>
);
export default layout;

Unable to pass prop back to parent component

I'm doing a simple test where I have a name state in the parent component which I update when a button in the child is clicked. But this does not work, and I'm confused on if I'm doing something wrong.
Parent:
import React from "react";
import "./styles.css";
import Hello from "./Hello";
export default function App() {
const [name, setName] = React.useState();
const handle = item => {
setName(item);
};
console.log(name);
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<Hello test={handle} />
{name}
</div>
);
}
Child:
import React from "react";
export default function App() {
return (
<div>
<button onclick={() => this.props.test("TEST")}>Activate Lasers</button>
</div>
);
}
What am I doing wrong?
Pass the function as a prop.
import React from "react";
export default function App({ handle }) {
return (
<div>
<button onClick={() => handle('TEST')}>Activate Lasers</button>
</div>
);
}
and render the component like
<Hello handle={handle} />
// Get a hook function
const {useState} = React;
function Hello({ handle }) {
return (
<div>
<button onClick={() => handle('TEST')}>Activate Lasers</button>
</div>
);
}
function App() {
const [name, setName] = React.useState();
const handle = item => {
setName(item);
};
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<Hello handle={handle} />
{name}
</div>
);
}
// Render it
ReactDOM.render(
<App />,
document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react"></div>
import React from "react";
export default function App(props) {
return (
<div>
<button onClick={() => props.test("TEST")}>Activate Lasers </button>
</div>
);
}
It should be onClick Secondly you are using this which is pointing to stateless component that is undefined and have no property props within it.
First:
React events are written in camelCase syntax:
onClick instead of onclick.
second
the keyword this in react usually used in-class component, and using it in a functional component to bind it with where you are using it, so now you need to pass the props to the child so that you can access the function.
this should work
import React from "react";
export default function Hello(props) {
return (
<div>
<button onClick={() => props.test("TEST")}>Activate Lasers</button>
</div>
);
}
and third try to use the same naming for thing :) to be more readable
I hope I helped you

Export named arrow function got "Object(...) is not a function" error

In a React app I wrote a function in file1.js and use this function in file2.js
// file1.js
export const withPrefix = (Component) => (props) => (
<PrefixContext.Consumer>
{prefix => <Component {...props} prefix={prefix}/>}
</PrefixContext.Consumer>
)
// file2.js
import { withPrefix } from '/path/to/file1.js'
let Toolbar = withPrefix(({prefix}) => ( // !error happens here
<Fragment>
<div style={{flexGrow: 1}}>
<Button><Link to={`${prefix}/create`}>New Artifact</Link></Button>
</div>
<Search style={{width: 200}}/>
</Fragment>
))
Then I got the error "TypeError: Object(...) is not a function". So I changed export withPrefix function
export function withPrefix(Component) {
return (props) => (
<PrefixContext.Consumer>
{prefix => <Component {...props} prefix={prefix}/>}
</PrefixContext.Consumer>
)
}
And the error is gone, everything works. But I wonder why these two exports result differently?
And another question is if I want to export an arrow function in es6, is the 2nd export function style the only method?
Attachment 1 (DefaultView.js):
import React, {Component} from 'react'
import {Layout} from 'antd'
import Toolbar from './Toolbar'
import Content from './Content'
export const PrefixContext = React.createContext()
export function withPrefix(Component) {
return (props) => (
<PrefixContext.Consumer>
{prefix => <Component {...props} prefix={prefix}/>}
</PrefixContext.Consumer>
)
}
export default class DefaultView extends Component {
constructor(props) {
super(props)
this.state = {
view: props.defaultView
}
}
handleViewChange = (view) => {
this.setState({view})
}
render() {
const {prefix, views} = this.props
const {view} = this.state
return (
<PrefixContext.Provider value={prefix}>
<Layout>
<Toolbar view={view} views={views} onViewChange=
{this.handleViewChange}/>
<hr/>
<Content view={view}/>
</Layout>
</PrefixContext.Provider>
)
}
}
Attachment 2 (Summary.js)
import React, {Component, Fragment} from 'react'
import {Button, Input} from 'antd'
import {Link} from 'react-router-dom'
import ArtifactTable from './ArtifactTable'
import {withPrefix} from "./DefaultView"
const {Search} = Input
export const Toolbar = withPrefix(({prefix}) => (
<Fragment>
<div style={{flexGrow: 1}}>
<Button><Link to={`${prefix}/create`}>新建软件包</Link></Button>
</div>
<Search style={{width: 200}}/>
</Fragment>
))
class Summary extends Component {
state = {
data: []
}
componentDidMount() {
const {prefix} = this.props
console.log('prefix=' + prefix)
fetch(prefix).then(json => {
this.setState({data: json.content})
})
}
render() {
const {data} = this.state
return (
<div>
<ArtifactTable data={data}/>
</div>
)
}
}
export default withPrefix(Summary)
Attachment 3 (Toolbar.js)
import React from 'react'
import {Switch, Route} from 'react-router-dom'
import {Toolbar as SummaryToolbar} from './Summary'
import Create from './Create'
import Details from './Details'
import Edit from './Edit'
import {withPrefix} from "./DefaultView"
const Toolbar = withPrefix(({prefix, view, onViewChange}) => (
<div style={{background: '#fff', padding: 16, display: 'flex',
alignItems: 'baseline'}}>
<Switch>
<Route exact path={`${prefix}`} component={SummaryToolbar}/>
<Route exact path={`${prefix}/create`}
component={() => <Create.Toolbar view={view} onViewChange=
{onViewChange}/>}/>
<Route exact path={`${prefix}/:id`}
component={() => <Details.Toolbar view={view} onViewChange=
{onViewChange}/>}/>
<Route exact path={`${prefix}/:id/edit`}
component={() => <Edit.Toolbar view={view} onViewChange=
{onViewChange}/>}/>
</Switch>
</div>
))
export default Toolbar
Update It's indeed the cyclic dependency problem as #Bergi and #loganfsmyth said. After I moved out
the withPrefix export snippet into a new file Context.js from DefaultView.js, the problem resolved. But I still have one quesion. In a cyclic dependency circumstances, why export const f = () => () => {} different from export function f() => { return () => {} }. Is export const lazy evaluated than export function as #loganfsmyth said?

react - get width/height of image to process

I was wondering how to get the height and width of an image if I'm rendering it react style so I can process it to flip it to portrait mode if the width is larger than the height.
Example: https://codesandbox.io/s/k9kwv0kp93
Example code:
index.js
import React from 'react';
import { render } from 'react-dom';
import Hello from './Hello';
const styles = {
fontFamily: 'sans-serif',
textAlign: 'center',
};
const App = () => (
<div style={styles}>
<Hello name="CodeSandbox" />
<h2>Start editing to see some magic happen {'\u2728'}</h2>
</div>
);
render(<App />, document.getElementById('root'));
Hello.js
import React, {Component} from 'react';
export default class Hello extends Component
{
constructor()
{
super();
this.state = {img: null}
this.get_image = this.get_image.bind(this);
}
get_image()
{
let img = <img src="http://via.placeholder.com/350x150" alt="" />;
//manipulate here maybe
this.setState({
img
})
}
render()
{
return (
<div>
<button onClick={this.get_image}>Click me</button>
test
{this.state.img}
</div>
)
}
}
I encountered the same issue, I was able to get the img height and width using ref and onLoad().
Class component version (with 'old' ref usage):
render() {
return (
<img
src='https://via.placeholder.com/150'
ref={el => this.imgEl = el}
onLoad={() => console.log(this.imgEl.naturalHeight)} // print 150
/>
)
}
Class component version (with 'new' ref):
import * as React from "react";
import ReactDOM from "react-dom";
class App extends React.Component {
imgEl = React.createRef();
render() {
return (
<img
src="https://via.placeholder.com/150"
ref={this.imgEl}
onLoad={() => console.log(this.imgEl.current.naturalHeight)} // print 150
/>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Functional component version:
import React from "react";
import ReactDOM from "react-dom";
function App() {
const imgElement = React.useRef(null);
return (
<img
src="https://via.placeholder.com/150"
ref={imgElement}
onLoad={() => console.log(imgElement.current.naturalHeight)} // print 150
/>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Also you should use img.naturalHeight
React supports a special attribute that you can attach to any component. The ref attribute takes a callback function, and the callback will be executed immediately after the component is mounted or unmounted.
When the ref attribute is used on an HTML element, the ref callback receives the underlying DOM element as its argument
Taken from: https://facebook.github.io/react/docs/refs-and-the-dom.html
class MyComponent extends React.Component {
constructor(props) {
super(props);
}
handleSize(image) {
console.log(image.offsetWidth, image.offsetHeight)
}
render() {
return React.createElement("img", {
src: "http://cdn.collider.com/wp-content/uploads/2016/07/narcos-season-2-image-5.jpg",
ref: image => {
this.handleSize(image);
},
onLoad=(image)=>this.handleSize(image);
});
}
}
ReactDOM.render(React.createElement(MyComponent, null), document.getElementById('root'))
img {
width: 200px;
height: 133px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-with-addons.min.js">
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

Categories

Resources