如何在Material-ui 4,React 16.8,TypeScript 3.5中使用Refs

时间:2019-08-05 19:15:00

标签: reactjs material-ui

我目前正在迁移到这些版本,现在我遇到了包含许多组件的forwardRef问题。有许多使用forwardRef的功能组件示例,但HOC类组件呢?也是非常大的嵌套HOC组件。

基础组件仅仅是使用材料ui输入的输入。

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}

该组件似乎失败了,或者是我不知道的那个组件。输入组件顶部的下一个组件是注释组件

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}

这只是更大的组件中的模式弹出窗口,该组件中包含数百个其他组件。

这是给定的错误

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

1 个答案:

答案 0 :(得分:2)

问题(或至少一个问题)与Slide过渡有关。它需要使用forwardRef

documentation中的示例如下所示:

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