Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Need help to send component reference #280

Closed
maitedev opened this issue Aug 26, 2020 · 19 comments
Closed

Need help to send component reference #280

maitedev opened this issue Aug 26, 2020 · 19 comments
Labels

Comments

@maitedev
Copy link

maitedev commented Aug 26, 2020

Hi, I am trying to use the react-to-print library in my application but without satisfactory results so far. I don't know how I should send the reference to the ReactToPrint component, I appreciate any suggestions. Grateful in advance.
Note: the component I want to print is the FormContent of type class .

    <Paper>
      <Grid container direction="column" spacing={1}>
        <Grid item xs={12}>
          <Grid container direction="row">
            <Grid item xs={6}>
              <FormTopLeft />
            </Grid>
            <Grid item xs={6}>
              <ReactToPrint
                trigger={() => (
                  <Tooltip title="Print">
                    <IconButton>
                      <PrintIcon />
                    </IconButton>
                  </Tooltip>
                )}
                content={() => this.componentRef}
              />
            </Grid>
          </Grid>
          <Divider/>
        </Grid>
        <Grid item xs={12}>
          <FormContent ref={el => (this.componentRef = el)} />
        </Grid>
      </Grid>
    </Paper>
@MatthewHerbst
Copy link
Owner

Hello. Your usage looks correct. Could you please explain what's not working? Are there any errors?

@maitedev
Copy link
Author

maitedev commented Aug 26, 2020

Thank you very much for responding so quickly !! In console it shows me the following error when I click the print button:

index.js:1 For "react-to-print" to work only Class based components can be printed.

I don't understand why, because the component where ReactToPrint is mounted is of type class, just like FormContent.
I must be doing something wrong but I don't realize that.

Sometimes he shows me this other:
index.js:1 Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?

@MatthewHerbst
Copy link
Owner

Is FormContent a class or functional component?

@maitedev
Copy link
Author

Yes, is a class component, which I am importing into the MainForm component.

@MatthewHerbst
Copy link
Owner

Do you mind sharing the full code for FormContent and for the component that wraps ReactToPrint?

@maitedev
Copy link
Author

maitedev commented Aug 27, 2020

MainForm: component that wraps ReactToPrint.

import React, { Component } from "react";
import { Grid, Paper, Divider, Tooltip, IconButton } from "@material-ui/core";
import PrintIcon from "@material-ui/icons/Print";
import FormContent from "./components/FormContent";
import FormTopLeft from "./components/FormTopLeft";
import ReactToPrint from "react-to-print";

class MainForm extends Component {
  render() {
    return (
      <Paper>
        <Grid container direction="column" spacing={1}>
          <Grid item xs={12}>
            <Grid container direction="row">
              <Grid item xs={6}>
                <FormTopLeft />
              </Grid>
              <Grid item xs={6}>
                <ReactToPrint
                  trigger={() => (
                    <Tooltip title="Print">
                      <IconButton>
                        <PrintIcon />
                      </IconButton>
                    </Tooltip>
                  )}
                  content={() => this.componentRef}
                />
              </Grid>
            </Grid>
            <Divider />
          </Grid>
          <Grid item xs={12}>
            <FormContent ref={(el) => (this.componentRef = el)} />
          </Grid>
        </Grid>
      </Paper>
    );
  }
}
export default MainForm;
import React, { Component, Fragment } from "react";
import { withRouter } from 'react-router-dom';
import { connect } from "react-redux";
import { Grid, TextField } from "@material-ui/core";
import * as globalVisibilityActions from "../../../../../../../store/actions/sync";
import * as currentObjectActions from "../../../../../../../store/actions/sync";
import * as apiCallActions from "../../../../../../../store/actions/async/apiCalls/general"

class FormContent extends Component {
  state = {
    max_capacity: 0,   
  }
  componentDidMount() {
    this.props.updateGlobalVisibilityViewType();
    this.setState({
      ...this.state,
      max_capacity: this.props.boxData.max_capacity,
    })
  };
  handleChange = event => {
    const targetField = event.target.name
    const targetValue = event.target.value
    this.props.updateCurrentObjectFieldsOnChange(targetField, targetValue);
  };
  render() {
    const { box_number } = this.props.boxData;
    const readOnly = this.props.isEditMode;
    const zone = this.props.boxData.zone ? this.props.boxData.zone : {}  
    return (
      <Fragment>
        <form>
          <Grid
            container
            direction="row"
            spacing={6}
            style={{ textAlign: "left" }}      
          >
            <Grid item xs={6}>
              <TextField
                inputProps={{
                  readOnly: Boolean(readOnly),
                  disabled: Boolean(readOnly),
                }}
                fullWidth
                name="box_number"
                type="number"
                label="Box number"
                value={box_number || ""}
                onChange={this.handleChange}
              />
            </Grid>
            <Grid item xs={6}>
              <TextField
                inputProps={{
                  readOnly: Boolean(true),
                  disabled: Boolean(true),
                }}
                fullWidth
                name="max_capacity"
                type="number"
                label="Max capacity"
                value={this.state.max_capacity || 0}
              />
            </Grid>
          </Grid>
        </form>
      </Fragment>
    );
  }
}

const mapStateToProps = state => {
  return {
    boxData: state.currentObject.currentObject,
    isEditMode: state.globalVisibility.isEditModeDisabled,  
  };
};

const mapDispatchToProps = dispatch => {
  const viewType = 'formType';
  return {
    updateGlobalVisibilityViewType: () => dispatch(globalVisibilityActions.updateGlobalVisibilityViewType(viewType)),
    updateCurrentObjectFieldsOnChange: (targetField, targetValue) => 
    dispatch(currentObjectActions.updateCurrentObjectFieldsOnChange(targetField, targetValue)),
};

export default withRouter(connect(mapStateToProps, mapDispatchToProps)(FormContent));

@MatthewHerbst
Copy link
Owner

Hmm. There are a few possible culprits. It's possible that withRouter returns a functional component instead of a class one. It's also possible that for some reason the Fragment is causing a problem. Could you try exporting the component without the router and/or changing the Fragment to a div?

@maitedev
Copy link
Author

I made both changes, I used a div and not Fragment and I did without the withRouter library.
When the component mount, it shows me the following error in the console:
index.js:1 Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use
React.forwardRef()?

When clicking on the print button, the same error continues:
index.js: 1 For "react-to-print" to work only Class based components can be printed.

@MatthewHerbst
Copy link
Owner

Very strange. Do you mind creating a codesandbox or similar with a full example so I can play with the code?

@maitedev
Copy link
Author

Today I prepare it.
I'm very sorry to be stealing your time.

@MatthewHerbst
Copy link
Owner

No problem at all, looking forward to solving the problem

@maitedev
Copy link
Author

maitedev commented Aug 28, 2020

Hi Matthew, here is the link of the test I did in codesandbox: https://codesandbox.io/s/zen-nash-xgkvn?file=/src/App.js

The only difference it has with the FormContent component, which I have in my project, is the use of Redux.
I tried to comment "react-redux" in my project, and the print worked correctly.

@maitedev
Copy link
Author

maitedev commented Sep 3, 2020

Hello, I wanted to know if the react-to-print library has any problem to work, if Redux is being used in the component that you want to print?

@MatthewHerbst
Copy link
Owner

Hi @maitedev not sure I follow? react-to-print uses no dependencies except for prop-types. It makes sense that connect from react-redux would be the problem. I think an easy solution would be to create a class component in the middle so that you can pass the class to ReactToPrint, and then the class will render the FormContent

@maitedev
Copy link
Author

maitedev commented Sep 16, 2020

Thank you very much Matthew, with that intermediate class that you suggested to me, I solved the problem. Thank you!!!

https://codesandbox.io/s/interesting-cookies-k1bg9?file=/src/deliverySheet/ComponentToPrint.js

@MatthewHerbst
Copy link
Owner

Glad you got it working! In the future we'll be able to support functional components, but doing so will require a breaking change so I'm trying to delay it as long as is reasonable.

@zedtux
Copy link

zedtux commented Nov 17, 2020

Thank you for this, I was in the same boat as @maitedev !

Would be great to add something on the README.md in order to inform about the issue with Redux 🙏

@MatthewHerbst
Copy link
Owner

@zedtux done! #316

@zedtux
Copy link

zedtux commented Nov 18, 2020

Awesome, thank you @MatthewHerbst !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants