I currently am migrating to these versions and now I am having a forwardRef isssue with many components. There are many examples for Function components using the forwardRef for them but what about HOC class components. Also very large nested HOC components.
Base component is just an input using material ui input.
import React, {Component} from 'react'
import {FormControl, Input, withStyles, createStyles} from '@material-ui/core'
const styles = (theme: any) => createStyles({
container: {
},
inputField: {
marginTop: 10,
marginBottom: -2,
fontSize: 18,
borderWidth: 1,
paddingLeft: 15,
paddingTop: 5,
paddingBottom: 5,
boxSizing: 'border-box' as any,
borderStyle: 'groove',
width: '100%',
},
textField: {
width: '100%',
margin: 0,
},
})
/*interface IStyles extends WithStyles<typeof styles> {
container: any
inputField: any
textField: any
}*/
interface ICommentBoxNoHEInjectedProps {
disabled?: boolean
path: string
value: any
placeholder?: string
rows: number
ref?: any
onChange: (newValue: any, path: string) => any
other?: any
}
interface ICommentBoxNoHEState {
value: any
}
interface ICommentBoxNoHEStyles {
classes: any
}
type CommentBoxNOHEProps = ICommentBoxNoHEInjectedProps & ICommentBoxNoHEStyles
class CommentBoxNoHE extends Component<CommentBoxNOHEProps, ICommentBoxNoHEState> {
constructor(props: CommentBoxNOHEProps) {
super(props)
this.state = {
value: '',
}
}
public componentWillUpdate(nextProps: any) {
if (nextProps.value !== this.props.value) {
this.setState(this.setValue(nextProps.value))
}
}
public componentWillMount() {
if (this.props.value) {
this.setState(this.setValue(this.props.value))
}
}
public setValue(newValue: any) {
return (state: Readonly<ICommentBoxNoHEState>, props: CommentBoxNOHEProps): any => {
return {value: newValue}
}
}
public handleOnChange(event: any) {
const value = event.target.value
this.props.onChange(value, this.props.path)
this.setState(this.setValue(value))
}
public render() {
const {classes, disabled, ref, placeholder, rows} = this.props
return (
<FormControl
className={classes.textField}
margin="dense"
fullWidth={true}
>
<Input className={classes.inputField}
disabled={disabled}
placeholder={placeholder}
value={this.state.value}
inputRef={ref}
fullWidth={true}
multiline={true}
type="text"
rows={rows}
onChange={this.handleOnChange}
/>
</FormControl>
)
}
}
// CommentBoxNo_H_E_component
const CommentBoxNo_H_E_component = withStyles(styles)(CommentBoxNoHE)
export {CommentBoxNo_H_E_component}
The component that seems to fail or is it this one I have no idea. Next component on top of this input component is a notes component
import React, {Component} from 'react'
import {IworkOrder} from '../../../api/models'
import Button from '@material-ui/core/Button'
import {withStyles, createStyles} from '@material-ui/core/styles'
import Slide from '@material-ui/core/Slide'
import DialogActions from '@material-ui/core/DialogActions'
import DialogContent from '@material-ui/core/DialogContent'
import DialogTitle from '@material-ui/core/DialogTitle'
import Dialog from '@material-ui/core/Dialog'
import {updateWO} from '../helpers'
import {debounce} from 'tedb-utils'
import {CommentBoxNo_H_E_component} from '../../../components'
const styles = (theme: any) => createStyles({
root: {
flexGrow: 1,
},
dialogPaper: {
minWidth: 600,
},
dialogTitle: {
fontSize: 30,
},
flatButton: {
width: '100%',
fontSize: 20,
},
dialogContent: {
fontSize: 20,
},
commentBox: {
margin: 10,
},
actionButtons: {
marginRight: 20,
marginBottom: 30,
},
})
interface INotesComponentStyles {
classes: any
}
interface INotesComponentInjectedProps {
keyValue: string
title: string
rows: number
currentWO: IworkOrder
open: boolean
placeholder: string
handleDialogClose: () => any
}
interface INotesComponentState {
note: any
}
export type NotesComponentProps = INotesComponentInjectedProps & INotesComponentStyles
/**
* New Feature in Material-UI. Need to include Slide as a component
* to be implemented in the Dialog component
* @param props
* @constructor
*/
function Transition(props: any) {
return <Slide direction="up" {...props} />
}
class NotesComponent extends Component<NotesComponentProps, INotesComponentState> {
public updateWO = updateWO
constructor(props: NotesComponentProps) {
super(props)
this.state = {
note: '',
}
this.isDisabled = this.isDisabled.bind(this)
this.handleInputChange = this.handleInputChange.bind(this)
this.clear = this.clear.bind(this)
}
public componentWillUpdate(nextProps: any, nextState: any) {
if (this.props.currentWO.misc[this.props.keyValue] !== this.state.note) {
this.setState(this.setValue(this.props.currentWO.misc[this.props.keyValue]))
}
}
public setValue(value: any) {
return (state: Readonly<INotesComponentState>, props: NotesComponentProps): any => ({note: value})
}
public isDisabled(): boolean {
return !!this.props.currentWO.timeSubmitted
}
public save(wo: any) {
this.updateWO(wo, wo._id)
.then((res) => {
console.log('saved')
})
.catch((err: any) => {
console.log(err)
})
}
public handleInputChange(value: string, key: string) {
const {currentWO} = this.props
currentWO.misc[key] = value
this.save(currentWO)
this.setState(this.setValue(value))
}
public clear() {
const {currentWO, keyValue} = this.props
currentWO.misc[keyValue] = ''
this.save(currentWO)
this.setState(this.setValue(''))
}
public render() {
const {classes} = this.props
return (
<Dialog
maxWidth="md"
classes={{
root: classes.root,
paper: classes.dialogPaper,
}}
onClose={this.props.handleDialogClose()}
open={this.props.open}
TransitionComponent={Transition}
>
<DialogTitle>
<div className={classes.dialogTitle}>
{this.props.title}
</div>
</DialogTitle>
<DialogContent className={classes.dialogContent}>
<div className={classes.commentBox}>
<CommentBoxNo_H_E_component
disabled={this.isDisabled()}
rows={this.props.rows}
placeholder={this.props.placeholder}
path={this.props.keyValue}
value={this.state.note}
onChange={debounce(this.handleInputChange, 500)}
/>
</div>
</DialogContent>
<DialogActions className={classes.actionButtons}>
<Button
className={classes.flatButton}
onClick={this.clear}
disabled={this.isDisabled()}
color="secondary"
variant={'contained'}
>
Clear
</Button>
<Button
className={classes.flatButton}
onClick={this.props.handleDialogClose()}
color="primary"
variant={'contained'}
>
Close
</Button>
</DialogActions>
</Dialog>
)
}
}
// NotesComponent_dialog
const NotesComponent_dialog = withStyles(styles)(NotesComponent)
export {NotesComponent_dialog}
This is just a modal popup in a much larger component housing hundreds of other components like this.
This is the given 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 `TrapFocus`.
in Transition (created by TrapFocus)
in 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 NotesComponent)
in NotesComponent (created by WithStyles(NotesComponent))
in WithStyles(NotesComponent) (created by Misc)
in div (created by Misc)
in Misc (created by WithStyles(Misc))
in WithStyles(Misc) (created by WO)
in div (created by ForwardRef(Grid))
in ForwardRef(Grid) (created by WithStyles(ForwardRef(Grid)))
in WithStyles(ForwardRef(Grid)) (created by WO)
in div (created by ForwardRef(Grid))
in ForwardRef(Grid) (created by WithStyles(ForwardRef(Grid)))
in WithStyles(ForwardRef(Grid)) (created by WO)
in div (created by ForwardRef(Grid))
in ForwardRef(Grid) (created by WithStyles(ForwardRef(Grid)))
in WithStyles(ForwardRef(Grid)) (created by WO)
in div (created by ForwardRef(Grid))
in ForwardRef(Grid) (created by WithStyles(ForwardRef(Grid)))
in WithStyles(ForwardRef(Grid)) (created by WO)
in div (created by ForwardRef(Grid))
in ForwardRef(Grid) (created by WithStyles(ForwardRef(Grid)))
in WithStyles(ForwardRef(Grid)) (created by WO)
in div (created by WO)
in WO (created by ConnectFunction)
in ConnectFunction (created by WithStyles(undefined))
in WithStyles(undefined) (created by Context.Consumer)
in Route (created by Routes)
in Switch (created by Routes)
in div (created by App)
in App (created by Routes)
in Routes (created by Root_container)
in ThemeProvider (created by Root_container)
in Router (created by ConnectedRouter)
in ConnectedRouter (created by Context.Consumer)
in ConnectedRouterWithContext (created by ConnectFunction)
in ConnectFunction (created by Root_container)
in Provider (created by Root_container)
in Root_container (created by App)
in div (created by App)
in App
The issue (or at least one issue) is with the Slide
transition. It needs to use forwardRef
.
The example in the documentation looks like the following:
import React from 'react';
import Slide from '@material-ui/core/Slide';
const Transition = React.forwardRef(function Transition(props, ref) {
return <Slide direction="up" ref={ref} {...props} />;
});
And the current (2020-03-05) TypeScript version in the documentation:
import React from 'react';
import Slide from '@material-ui/core/Slide';
import { TransitionProps } from '@material-ui/core/transitions';
const Transition = React.forwardRef<unknown, TransitionProps>(function Transition(props, ref) {
return <Slide direction="up" ref={ref} {...props} />;
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With