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

Can I use it without ref in functional components #363

Closed
truelet opened this issue Apr 30, 2021 · 15 comments
Closed

Can I use it without ref in functional components #363

truelet opened this issue Apr 30, 2021 · 15 comments
Labels

Comments

@truelet
Copy link

truelet commented Apr 30, 2021

If is it possible, Can I have any example by doing this.

@MatthewHerbst
Copy link
Owner

Hello. What is the problem you are facing with refs?

@truelet
Copy link
Author

truelet commented Apr 30, 2021

I am facing bellow error.

Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?

Check the render method of `WithStyles(memo(PreviewChallan))`.
    in PreviewChallan (created by WithStyles(memo(PreviewChallan)))
    in WithStyles(memo(PreviewChallan)) (created by ViewChallan)
    in div (created by ForwardRef(DialogContent))
    in ForwardRef(DialogContent) (created by WithStyles(ForwardRef(DialogContent)))
    in WithStyles(ForwardRef(DialogContent)) (created by ViewChallan)
    in div (created by ForwardRef(Paper))
    in ForwardRef(Paper) (created by WithStyles(ForwardRef(Paper)))
    in WithStyles(ForwardRef(Paper)) (created by ForwardRef(Dialog))
    in div (created by Transition)
    in Transition (created by ForwardRef(Slide))
    in ForwardRef(Slide) (created by ForwardRef(Transition))
    in ForwardRef(Transition) (created by Unstable_TrapFocus)
    in Unstable_TrapFocus (created by ForwardRef(Modal))
    in div (created by ForwardRef(Modal))
    in ForwardRef(Portal) (created by ForwardRef(Modal))
    in ForwardRef(Modal) (created by ForwardRef(Dialog))
    in ForwardRef(Dialog) (created by WithStyles(ForwardRef(Dialog)))
    in WithStyles(ForwardRef(Dialog)) (created by ViewChallan)
    in div (created by ViewChallan)
    in ViewChallan (created by WithStyles(ViewChallan))
    in WithStyles(ViewChallan) (created by ListChallans)
    in div (created by ListChallans)
    in ListChallans (created by WithStyles(ListChallans))
    in WithStyles(ListChallans) (created by Challans)
    in div (created by Challans)
    in Challans (created by WithStyles(memo(Challans)))
    in WithStyles(memo(Challans)) (created by Layout)
    in Route (created by Layout)
    in Switch (created by Layout)
    in div (created by Layout)
    in main (created by Layout)
    in div (created by Layout)
    in Layout (created by WithStyles(memo(Layout)))
    in WithStyles(memo(Layout)) (created by Routes)
    in Route (created by Routes)
    in Switch (created by Routes)
    in ThemeProvider (created by Routes)
    in Router (created by BrowserRouter)
    in BrowserRouter (created by Routes)
    in div (created by Routes)
    in Routes
    in div
    in Provider
    in div
printWarning @ app.js:295985
error @ app.js:295957
validateFunctionComponentInDev @ app.js:313475
updateMemoComponent @ app.js:312755
beginWork @ app.js:314579
beginWork$1 @ app.js:319076
performUnitOfWork @ app.js:318054
workLoopSync @ app.js:318027
performSyncWorkOnRoot @ app.js:317653
(anonymous) @ app.js:306986
unstable_runWithPriority @ app.js:333971
runWithPriority$1 @ app.js:306936
flushSyncCallbackQueueImpl @ app.js:306981
flushSyncCallbackQueue @ app.js:306969
scheduleUpdateOnFiber @ app.js:317096
dispatchAction @ app.js:311557
(anonymous) @ app.js:339423
Promise.then (async)
loadData @ app.js:339416
(anonymous) @ app.js:339436
commitHookEffectListMount @ app.js:315628
commitPassiveHookEffects @ app.js:315666
callCallback @ app.js:296085
invokeGuardedCallbackDev @ app.js:296134
invokeGuardedCallback @ app.js:296189
flushPassiveEffectsImpl @ app.js:318750
unstable_runWithPriority @ app.js:333971
runWithPriority$1 @ app.js:306936
flushPassiveEffects @ app.js:318717
performSyncWorkOnRoot @ app.js:317634
(anonymous) @ app.js:306986
unstable_runWithPriority @ app.js:333971
runWithPriority$1 @ app.js:306936
flushSyncCallbackQueueImpl @ app.js:306981
flushSyncCallbackQueue @ app.js:306969
discreteUpdates$1 @ app.js:317790
discreteUpdates @ app.js:296703
dispatchDiscreteEvent @ app.js:300065
app.js:324472 For "react-to-print" to work only Class based components can be printed.

@truelet
Copy link
Author

truelet commented Apr 30, 2021

I wanted to print a material UI table which open dynamically with data and then I want to print that table.
react-to-print

@MatthewHerbst
Copy link
Owner

Could you please share some of your code, or ideally a code sandbox replicating the problem? The error is correct though. There may be some workarounds. See this #96 and #181 for solutions others have come up with

@truelet
Copy link
Author

truelet commented May 1, 2021

This is main component:

import React, { useState, useEffect, Fragment, useRef } from "react";
import { useSelector, useDispatch } from "react-redux";
import printJS from 'print-js';
import ReactToPrint from 'react-to-print';
import { AppLoaderAction, AppAlertAction } from "../../../redux/actions/appAction";
import CloseIcon from "@material-ui/icons/Close";

import { 
  Grid,
  Typography,
  IconButton,
  withStyles,
  Dialog,
  DialogTitle,
  DialogContent,
  Slide,
} from "@material-ui/core";

import { getChallanDetails } from "../../../services/Challan";
import PreviewChallan from "./PreviewChallan";

const styles = (theme) => ({
  dialogTitle: {
    flexGrow: 1,
  },
  scrollPaper: {
    alignItems: 'baseline'  // default center
  },
});

const Transition = React.forwardRef(function Transition(props, ref) {
  return <Slide direction="down" ref={ref} {...props} />;
});

const initialState = {
};

const ViewChallan = (props)=> {
  const componentRef = useRef();
  const { classes, open, handleClose, challan_id} = props;
  const dispatch = useDispatch();
  const [state, setState] = React.useState(initialState);
  const [challanData, setChallanData] = React.useState(null);

  const loadData = (params) => {
    // get parties data
    dispatch(AppLoaderAction(true));
    getChallanDetails(params).then((response) => {
      dispatch(AppLoaderAction(false));
      if(response.status) {
        let data = response.data;
        if(data) {
          setChallanData(data);
        }
      } else {
        dispatch(AppAlertAction({'status': true, 'type': 'error', 'message': response.message}));
      }
    });
  };

  useEffect(() => {
    loadData({id:challan_id});
  }, [open]);

  useEffect(() => {
    
    }
  }, [challanData]);

return (
    <div>
      <Dialog 
        onClose={handleClose}
        aria-labelledby="customized-dialog-title"
        open={open}
        fullWidth={true}
        maxWidth='md'
        scroll='body'
        TransitionComponent={Transition}
        disableBackdropClick={true}
        disableEscapeKeyDown={true}
        className="align-top"
        >
          <DialogTitle disableTypography className={classes.dialogTitle}>
              <Grid container spacing={1}>
                <Grid item xs={12} sm={12} md={12} lg={12}>
                <Typography variant="h6">Print Challan</Typography>
                </Grid>
              </Grid>
              {open ? (
                  <IconButton aria-label="close" className="dialogCloseButton" onClick={handleClose}>
                  <CloseIcon />
                  </IconButton>
              ) : null}
          </DialogTitle>
          <DialogContent dividers>
              <Fragment>
              <ReactToPrint
                trigger={() => <button>Print this out!</button>}
                content={() => componentRef.current}
              />
                {(challanData != null)?
                  <PreviewChallan data={challanData} ref={componentRef}/>
                :false
                }
              </Fragment>
          </DialogContent>
      </Dialog>
    </div>
  )
}

export default withStyles(styles, { withTheme: true })(ViewChallan);

This is Printable component which is also functional based:

import React, { memo, useState, useEffect, Fragment } from "react";
import { useSelector, useDispatch } from "react-redux";
import { 
  Grid,
  Divider,
  Typography,
  IconButton,
  Button,
  withStyles,
  TextField,
  FormControl,
  Table,
  TableBody,
  TableCell,
  TableContainer,
  TableRow,
  TableHead,
  TableFooter,
} from "@material-ui/core";
import DateFnsUtils from '@date-io/date-fns';
import {
  MuiPickersUtilsProvider,
  KeyboardDatePicker,
} from '@material-ui/pickers';

import { CONFIG } from '../../../config';
import { getUserData } from "../../../services/Auth";

const styles = (theme) => ({
});

const PreviewChallan = (props)=> {
  const { classes, data, challan_date, handlePreviewChange, handlePreviewDateChange } = props;
  const dispatch = useDispatch();
  const userData = getUserData();

  useEffect(() => {

  },[]);

  return (
    <div>
      {/* <Toolbar className="toolbar-heading">
          <Typography className="list-title" color="inherit" variant="h6" component="div">Challan Preview</Typography>
      </Toolbar> */}
      <TableContainer className="table-container" align="center" id="preview_challan">
        <Table className="table-border width-99" size="small" aria-label="preview table">
          <TableHead>
            {(data.is_show_company)?
            <TableRow>
              <TableCell align="center" className="table-cell-p2 no-border" colSpan={(data.header2.length)+3}>
                <Typography variant="h6" component="h6" color="secondary">
                  <b>{userData.company_name}</b>
                </Typography>
              </TableCell>
            </TableRow>
            :false
            }
            <TableRow>
              {(data.id == '' && data.is_edit_challan)?
                <TableCell colSpan={2} className="table-cell-p2 no-border">
                  <Grid container spacing={0}>
                    <Grid item xs={4} sm={4} md={4} lg={3}><Typography variant="body1" color="secondary"><b>Challan No : </b></Typography></Grid>
                    <Grid item xs={4} sm={4} md={4} lg={4}>
                      <FormControl variant="outlined">
                          <TextField
                            label=""
                            variant="outlined"
                            color="primary"
                            size="small"
                            onChange={handlePreviewChange}
                            value={data.challan_no}
                            name="challan_no"
                            autoComplete="off"
                            type="number"
                            inputProps={{'className': 'price-psm'}}
                            className="price-field-xsm"
                          />
                        </FormControl>
                        </Grid>
                  </Grid>
                </TableCell>
              :
                <TableCell colSpan={2} className="table-cell-p2 no-border"><Typography variant="body1" color="secondary"><b>Challan No : {data.challan_no}</b></Typography></TableCell>
              }
              {(data.id == '' && data.is_edit_date)?
                <TableCell colSpan={data.header2.length+1} className="table-cell-p2 no-border" align="right">
                  <Grid container spacing={0}>
                    <Grid item xs={8} sm={8} md={8} lg={9} align="right"><Typography variant="body1" color="secondary"><b>Date : </b></Typography></Grid>
                    <Grid item xs={4} sm={4} md={4} lg={3}>
                      <MuiPickersUtilsProvider utils={DateFnsUtils}>
                        <KeyboardDatePicker
                          autoOk
                          fullWidth
                          disableToolbar
                          variant="inline"
                          inputVariant="outlined"
                          format="dd-MMM-yyyy"
                          margin="none"
                          label=""
                          size="small"
                          value={challan_date}
                          onChange={handlePreviewDateChange}
                          KeyboardButtonProps={{
                            'aria-label': 'change date',
                          }}
                          invalidDateMessage=''
                          inputProps={{disabled: true, 'className': 'price-psm'}}
                          className="price-field-xsm"
                        />
                    </MuiPickersUtilsProvider>
                  </Grid>
                </Grid>
              </TableCell>
              :
                <TableCell colSpan={data.header2.length+1} className="table-cell-p2 no-border" align="right"><Typography variant="body1" color="secondary"><b>Date : {data.challan_date}</b></Typography></TableCell>
              }
            </TableRow>
            <TableRow>
              <TableCell colSpan={(data.header2.length)+3} className="table-cell-p2 no-border">To : {data.party_code}</TableCell>
            </TableRow>
            <TableRow>
              {data.header1.map((row, index) => (
                <TableCell
                  key={index}
                  align={row.align ? row.align : (row.numeric ? "right" : "inherit")}
                  padding="default"
                  className='table-cell-p2 border bg-graey'
                  style={{maxWidth: (row.maxWidth != undefined)?row.maxWidth:'', minWidth: (row.minWidth != undefined)?(row.minWidth+'px !important'):''}}
                  colSpan={(row.colSpan)?row.colSpan:''}
                  rowSpan={(row.rowSpan)?row.rowSpan:''}
                  dangerouslySetInnerHTML={{__html: row.label}}
                >
                </TableCell>
              ))}
            </TableRow>
            <TableRow>
              {data.header2.map((row, index) => (
                <TableCell
                  key={index}
                  align={row.align ? row.align : (row.numeric ? "right" : "inherit")}
                  padding="default"
                  className='table-cell-p2 border bg-graey'
                  style={{maxWidth: (row.maxWidth != undefined)?row.maxWidth:'', minWidth: (row.minWidth != undefined)?(row.minWidth+'px !important'):''}}
                  colSpan={(row.colSpan)?row.colSpan:''}
                  rowSpan={(row.rowSpan)?row.rowSpan:''}                
                >
                  {row.label}
                </TableCell>
              ))}
            </TableRow>
          </TableHead>
          <TableBody>
          {data.files.map((row, index) => {
            return (
              <TableRow key={"body_"+index}>
                <TableCell className="table-cell-p2 border">{index+1}</TableCell>
                <TableCell className="table-cell-p2 border">{row.name} <b>{(row.cad_option == CONFIG.FILES_CAD_OPTIONS_VALUES.CAD)?"("+CONFIG.FILES_CAD_OPTIONS_ID[row.cad_option]+")":''}</b></TableCell>
                {(data.file_types.indexOf(CONFIG.FILE_TYPES.CAM) != -1)?
                  <TableCell className="table-cell-p2 border" align="right">
                    <span>{row.cam_weight_apl}</span>
                    {(row.show_min_cam_weight)?
                      <span>({row.cam_weight_act})</span>
                    :false
                    }
                  </TableCell>
                :false
                }
                {(data.file_types.indexOf(CONFIG.FILE_TYPES.DIE) != -1)?
                  <TableCell className="table-cell-p2 border" align="right">
                    <span>{row.die_weight_apl}</span>
                    {(row.show_min_die_weight)?
                      <span>({row.die_weight_act})</span>
                    :false
                    }
                  </TableCell>
                :false
                }
                {(data.file_types.indexOf(CONFIG.FILE_TYPES.RWX) != -1)?
                  <TableCell className="table-cell-p2 border" align="right">
                    <span>{row.rwx_weight_apl}</span>
                    {(row.show_min_rwx_weight)?
                      <span>({row.rwx_weight_act})</span>
                    :false
                    }
                  </TableCell>
                :false
                }
                {(data.file_types.indexOf(CONFIG.FILE_TYPES.CPX) != -1)?
                  <TableCell className="table-cell-p2 border" align="right">
                    <span>{row.cpx_weight_apl}</span>
                    {(row.show_min_cpx_weight)?
                      <span>({row.cpx_weight_act})</span>
                    :false
                    }
                  </TableCell>
                :false
                }
                {(data.file_types.indexOf(CONFIG.FILE_TYPES.CAST) != -1)?
                  <TableCell className="table-cell-p2 border" align="right">
                    <span>{row.casting_weight_apl}</span>
                    {(row.show_min_casting_weight)?
                      <span>({row.casting_weight_act})</span>
                    :false
                    }
                  </TableCell>
                :false
                }
                {/* Price Table Cell */}
                {(data.file_types.indexOf(CONFIG.FILE_TYPES.CAD) != -1)?
                  <TableCell className="table-cell-p2 border" align="right">
                    <span>{row.cad_price}</span>
                  </TableCell>
                :false
                }
                {(data.file_types.indexOf(CONFIG.FILE_TYPES.CAM) != -1)?
                  <TableCell className="table-cell-p2 border" align="right">
                    <span>{row.cam_price}</span>
                  </TableCell>
                :false
                }
                {(data.file_types.indexOf(CONFIG.FILE_TYPES.DIE) != -1)?
                  <TableCell className="table-cell-p2 border" align="right">
                    <span>{row.die_price}</span>
                  </TableCell>
                :false
                }
                {(data.file_types.indexOf(CONFIG.FILE_TYPES.RWX) != -1)?
                  <TableCell className="table-cell-p2 border" align="right">
                    <span>{row.rwx_price}</span>
                  </TableCell>
                :false
                }
                {(data.file_types.indexOf(CONFIG.FILE_TYPES.CPX) != -1)?
                  <TableCell className="table-cell-p2 border" align="right">
                    <span>{row.cpx_price}</span>
                  </TableCell>
                :false
                }
                {(data.file_types.indexOf(CONFIG.FILE_TYPES.CAST) != -1)?
                  <TableCell className="table-cell-p2 border" align="right">
                    <span>{row.casting_price}</span>
                  </TableCell>
                :false
                }
                <TableCell className="table-cell-p2 border" align="right">
                  <span>{row.extra_price}</span>
                </TableCell>
                <TableCell className="table-cell-p2 border" align="right">
                  <span>{row.total_price}</span>
                </TableCell>
              </TableRow>
            )
          })}
          <TableRow>
            <TableCell align="center" className="table-cell-p2 border" colSpan={(data.header2.length)+3}>&nbsp;</TableCell>
          </TableRow>
          </TableBody>
          {/* Sub Total and weight total row */}
          <TableHead>
            <TableRow>
              {(data.is_show_total_weight)?
                <Fragment>
                  <TableCell className="table-cell-p2 border" colSpan={2} align="right">Total</TableCell>
                  {(data.file_types.indexOf(CONFIG.FILE_TYPES.CAM) != -1)?
                    <TableCell className="table-cell-p2 border" className="table-cell-p2 border" align="right">
                      <span>{data.total_weight[CONFIG.FILE_TYPES.CAM]}</span>
                    </TableCell>
                  :false
                  }
                  {(data.file_types.indexOf(CONFIG.FILE_TYPES.DIE) != -1)?
                    <TableCell className="table-cell-p2 border" className="table-cell-p2 border" align="right">
                      <span>{data.total_weight[CONFIG.FILE_TYPES.DIE]}</span>
                    </TableCell>
                  :false
                  }
                  {(data.file_types.indexOf(CONFIG.FILE_TYPES.RWX) != -1)?
                    <TableCell className="table-cell-p2 border" className="table-cell-p2 border" align="right">
                      <span>{data.total_weight[CONFIG.FILE_TYPES.RWX]}</span>
                    </TableCell>
                  :false
                  }
                  {(data.file_types.indexOf(CONFIG.FILE_TYPES.CPX) != -1)?
                    <TableCell className="table-cell-p2 border" className="table-cell-p2 border" align="right">
                      <span>{data.total_weight[CONFIG.FILE_TYPES.CPX]}</span>
                    </TableCell>
                  :false
                  }
                  {(data.file_types.indexOf(CONFIG.FILE_TYPES.CAST) != -1)?
                    <TableCell className="table-cell-p2 border" className="table-cell-p2 border" align="right">
                      <span>{data.total_weight[CONFIG.FILE_TYPES.CAST]}</span>
                    </TableCell>
                  :false
                  }
                  <TableCell className="table-cell-p2 border" colSpan={(Object.keys(data.total_weight)).length+3-4}></TableCell>
                  <TableCell className="table-cell-p2 border" colSpan={3} align="right">Sub Total</TableCell>
                  <TableCell className="table-cell-p2 border" align="right">{data.sub_total}</TableCell>
                </Fragment>
                :
                <TableCell className="table-cell-p2 border" colSpan={data.header2.length+3-4} align="right"></TableCell>
              }
            </TableRow>
            {(data.is_show_courier_charges)?
              <TableRow>
                <TableCell className="table-cell-p2 border" colSpan={data.header2.length+3-4} align="right"></TableCell>
                <TableCell className="table-cell-p2 border" colSpan={3} align="right">Courier Charges</TableCell>
                <TableCell className="table-cell-p2 border" align="right">{data.charges}</TableCell>
              </TableRow>
            :
            false
            }
            <TableRow>
              <TableCell className="table-cell-p2 border" colSpan={data.header2.length+3-4} align="center">
                {(data.is_show_due_files_count)?
                  <span>Due Files : {data.due_files_count}</span>
                :''
                }
              </TableCell>
              <TableCell className="table-cell-p2 border" colSpan={3} align="right">Grand Total</TableCell>
              <TableCell className="table-cell-p2 border" align="right">{data.grand_total}</TableCell>
            </TableRow>
          </TableHead>
          {(data.footer_note)?
            <TableBody>
              <TableRow>
                <TableCell align="left" className="table-cell-p2 border" colSpan={(data.header2.length)+3}>{data.footer_note}</TableCell>
              </TableRow>
            </TableBody>
          :false
          }
          {(data.is_receiver_signature || data.is_sender_signature)?
            <TableHead>
              <TableRow>
                <TableCell align="left" className="table-cell-p2 border" colSpan={Math.floor(((data.header2.length)+3)/2)}>
                {(data.is_receiver_signature)?
                  <Fragment>
                    <div className="signature-border pull-left">&nbsp;</div>
                    <div className="signature-text">Received By</div>
                  </Fragment>
                :''
                }
                </TableCell>
                <TableCell align="right" className="table-cell-p2 border" colSpan={Math.ceil(((data.header2.length)+3)/2)}>
                  {(data.is_sender_signature)?
                    <Fragment>
                      <div className="signature-border pull-right">&nbsp;</div>
                      <div className="signature-text">Authorized Sign.</div>
                    </Fragment>
                  :''
                  }
                </TableCell>
              </TableRow>
            </TableHead>
          :false
          }
        </Table>
        <br/>
      </TableContainer>
    </div>
  )
}

export default withStyles(styles, { withTheme: true })(memo(PreviewChallan));

All the parent components are functional components.

So, How can I use with my components.

@MatthewHerbst
Copy link
Owner

Two options, as noted in #96: you can wrap the entire component to print in a native dom element such as a div, or you can wrap the entire component to print in the React.forwardRef HOC

@truelet
Copy link
Author

truelet commented May 4, 2021

I have converted print component into forward ref like component. And now I am facing below issue when click on print button.
For "react-to-print" to work only Class based components can be printed.

@truelet
Copy link
Author

truelet commented May 5, 2021

At the end I have converted my print component into class component and now the print is working.
I want to open print dialog on component open, not on button click, for this what should i have to do?

@MatthewHerbst
Copy link
Owner

I'm glad you were able to get it working using a class component. I hope to have better support for functional components in the next major version of the package.

on component open

I'm not sure I understand. Do you mean when the component renders?

@truelet
Copy link
Author

truelet commented May 6, 2021

I have find solution for this too, thanks for your support, will get touch in future if needed.

@MatthewHerbst
Copy link
Owner

Glad you found a solution! Please feel free to reach out if you run into any other issues. Have a good day 😄

@jackywq
Copy link

jackywq commented Jul 29, 2021

I have converted print component into forward ref like component. And now I am facing below issue when click on print button.

me too, How to solve such problems,Please?

@MatthewHerbst
Copy link
Owner

@jackywq the best solution for now is to use a class-based component

@el2king
Copy link

el2king commented Sep 7, 2021

I have a question in relation to this. I am using a functional component with ref, as I have to use a hook (useLocation).

As such, for the componentRef, I am using this statement to create it:

const componentRef = React.createRef<_type_omitted_>()

I am trying to use a list of objects with .map, but as I've read before, I need to use some indexing to allow for the componentRef not to be overwritten with just the last object in the .map.

I tried some variations with the index, but nothing is working. How would be possible to use indexes with componentRef with using a list of objects with .map?

@tommy-banana
Copy link

Any progress on using this with functional components?

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

5 participants