反应高阶组件在打字稿中不起作用
React higher order component not working in typescript
问题
我正在尝试将 HOC 从 javascript 提升到打字稿。 HOC 在使用它的组件中添加了一个确认对话框,提供了一个 prop showConfirmationDialog
,它在被调用时显示对话框并在点击确认时运行回调。
代码编译正常,但是当我在浏览器中打开应用程序时,出现错误"Invalid hook call. Hooks can only be called inside of the body of a function component."
代码在 javascript 中运行良好。我无法理解该错误,我已按照所有建议的步骤进行操作,但仍无法解决问题。
代码
ConfirmationDialog/index.tsx
type ExtraProps = {
showConfirmationDialog: (params: RequiredParameters) => void
}
type ConfirmationCallback = () => void
interface RequiredParameters {
dialogTitle: string,
dialogContent: string,
confirmationButtonText: string,
onConfirm: ConfirmationCallback
}
const WithConfirmationDialog = <P extends ExtraProps>(Component: React.ComponentType<P>) => {
const [open, setOpen] = useState(false)
const [title, setTitle] = useState('')
const [content, setContent] = useState('')
const [confirmationButtonText, setConfirmationButtonText] = useState('')
const [onConfirm, setOnConfirm] = useState<ConfirmationCallback>()
const handleShow = (params: RequiredParameters) => {
setTitle(params.dialogTitle)
setContent(params.dialogContent)
setConfirmationButtonText(params.confirmationButtonText)
setOnConfirm(params.onConfirm)
setOpen(true)
}
const handleConfirm = () => {
if (onConfirm) {
onConfirm()
}
setOpen(false)
}
const handleClose = () => {
setOpen(false)
}
const ComponentWithConfirmationDialog = (props: P) => (
<>
<Dialog
open={open}
onClose={handleClose}
>
<DialogTitle>{title}</DialogTitle>
<DialogContent>
<DialogContentText>{content} </DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={handleConfirm} color="primary">
{confirmationButtonText}
</Button>
<Button onClick={handleClose} color="primary">
Cancel
</Button>
</DialogActions>
</Dialog>
<Component {...props} showConfirmationDialog={handleShow} />
</>
)
return ComponentWithConfirmationDialog
}
export default WithConfirmationDialog
单击另一个组件中的按钮后使用代码的示例:
import withConfirmationDialog from '../ConfirmationDialog'
const MyComponent = (props) => {
const classes = useStyles();
const handleDeleteBooking = () => {
// ...make api calls and handle results...
};
// left out everything else for brevity
return (
<Fab // material-ui
className={classes.deleteButton}
aria-label="delete"
onClick={(e) => {
props.showConfirmationDialog({
dialogTitle: "Delete Booking",
dialogContent: "Are you sure you want to delete this booking?",
confirmationButtonText: "Delete",
onConfirm: handleDeleteBooking,
});
}}
>
<DeleteIcon /> // material-ui
</Fab>
);
};
export default withConfirmationDialog(MyComponent)
附加信息
我用来构建这个的主要指南可以是found here。
当 运行 npm start
编译正常时,错误永远不会显示在终端中。
我在浏览器中只看到 'Invalid hook call' 消息,以及指向我在 HOC 中首次使用 useState(false
的堆栈跟踪。
如有任何帮助,我们将不胜感激!
这里的问题是您的 HOC 正在函数组件之外调用挂钩 ComponentWithConfirmationDialog
。所有钩子都必须在组件内部调用,而不是外部。您的 HOC 函数本身不是组件。
为了解决这个问题,您需要将 ComponentWithConfirmationDialog
上方的所有内容移动到其中,例如:
const WithConfirmationDialog = <P extends ExtraProps>(Component: React.ComponentType<P>) => {
const ComponentWithConfirmationDialog = (props: P) => {
const [open, setOpen] = useState(false)
const [title, setTitle] = useState('')
const [content, setContent] = useState('')
const [confirmationButtonText, setConfirmationButtonText] = useState('')
const [onConfirm, setOnConfirm] = useState<ConfirmationCallback>()
const handleShow = (params: RequiredParameters) => {
setTitle(params.dialogTitle)
setContent(params.dialogContent)
setConfirmationButtonText(params.confirmationButtonText)
setOnConfirm(params.onConfirm)
setOpen(true)
}
const handleConfirm = () => {
if (onConfirm) {
onConfirm()
}
setOpen(false)
}
const handleClose = () => {
setOpen(false)
}
return (
<>
<Dialog
open={open}
onClose={handleClose}
>
<DialogTitle>{title}</DialogTitle>
<DialogContent>
<DialogContentText>{content} </DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={handleConfirm} color="primary">
{confirmationButtonText}
</Button>
<Button onClick={handleClose} color="primary">
Cancel
</Button>
</DialogActions>
</Dialog>
<Component {...props} showConfirmationDialog={handleShow} />
</>
)
}
return ComponentWithConfirmationDialog
}
export default WithConfirmationDialog
问题
我正在尝试将 HOC 从 javascript 提升到打字稿。 HOC 在使用它的组件中添加了一个确认对话框,提供了一个 prop showConfirmationDialog
,它在被调用时显示对话框并在点击确认时运行回调。
代码编译正常,但是当我在浏览器中打开应用程序时,出现错误"Invalid hook call. Hooks can only be called inside of the body of a function component."
代码在 javascript 中运行良好。我无法理解该错误,我已按照所有建议的步骤进行操作,但仍无法解决问题。
代码
ConfirmationDialog/index.tsx
type ExtraProps = {
showConfirmationDialog: (params: RequiredParameters) => void
}
type ConfirmationCallback = () => void
interface RequiredParameters {
dialogTitle: string,
dialogContent: string,
confirmationButtonText: string,
onConfirm: ConfirmationCallback
}
const WithConfirmationDialog = <P extends ExtraProps>(Component: React.ComponentType<P>) => {
const [open, setOpen] = useState(false)
const [title, setTitle] = useState('')
const [content, setContent] = useState('')
const [confirmationButtonText, setConfirmationButtonText] = useState('')
const [onConfirm, setOnConfirm] = useState<ConfirmationCallback>()
const handleShow = (params: RequiredParameters) => {
setTitle(params.dialogTitle)
setContent(params.dialogContent)
setConfirmationButtonText(params.confirmationButtonText)
setOnConfirm(params.onConfirm)
setOpen(true)
}
const handleConfirm = () => {
if (onConfirm) {
onConfirm()
}
setOpen(false)
}
const handleClose = () => {
setOpen(false)
}
const ComponentWithConfirmationDialog = (props: P) => (
<>
<Dialog
open={open}
onClose={handleClose}
>
<DialogTitle>{title}</DialogTitle>
<DialogContent>
<DialogContentText>{content} </DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={handleConfirm} color="primary">
{confirmationButtonText}
</Button>
<Button onClick={handleClose} color="primary">
Cancel
</Button>
</DialogActions>
</Dialog>
<Component {...props} showConfirmationDialog={handleShow} />
</>
)
return ComponentWithConfirmationDialog
}
export default WithConfirmationDialog
单击另一个组件中的按钮后使用代码的示例:
import withConfirmationDialog from '../ConfirmationDialog'
const MyComponent = (props) => {
const classes = useStyles();
const handleDeleteBooking = () => {
// ...make api calls and handle results...
};
// left out everything else for brevity
return (
<Fab // material-ui
className={classes.deleteButton}
aria-label="delete"
onClick={(e) => {
props.showConfirmationDialog({
dialogTitle: "Delete Booking",
dialogContent: "Are you sure you want to delete this booking?",
confirmationButtonText: "Delete",
onConfirm: handleDeleteBooking,
});
}}
>
<DeleteIcon /> // material-ui
</Fab>
);
};
export default withConfirmationDialog(MyComponent)
附加信息
我用来构建这个的主要指南可以是found here。
当 运行 npm start
编译正常时,错误永远不会显示在终端中。
我在浏览器中只看到 'Invalid hook call' 消息,以及指向我在 HOC 中首次使用 useState(false
的堆栈跟踪。
如有任何帮助,我们将不胜感激!
这里的问题是您的 HOC 正在函数组件之外调用挂钩 ComponentWithConfirmationDialog
。所有钩子都必须在组件内部调用,而不是外部。您的 HOC 函数本身不是组件。
为了解决这个问题,您需要将 ComponentWithConfirmationDialog
上方的所有内容移动到其中,例如:
const WithConfirmationDialog = <P extends ExtraProps>(Component: React.ComponentType<P>) => {
const ComponentWithConfirmationDialog = (props: P) => {
const [open, setOpen] = useState(false)
const [title, setTitle] = useState('')
const [content, setContent] = useState('')
const [confirmationButtonText, setConfirmationButtonText] = useState('')
const [onConfirm, setOnConfirm] = useState<ConfirmationCallback>()
const handleShow = (params: RequiredParameters) => {
setTitle(params.dialogTitle)
setContent(params.dialogContent)
setConfirmationButtonText(params.confirmationButtonText)
setOnConfirm(params.onConfirm)
setOpen(true)
}
const handleConfirm = () => {
if (onConfirm) {
onConfirm()
}
setOpen(false)
}
const handleClose = () => {
setOpen(false)
}
return (
<>
<Dialog
open={open}
onClose={handleClose}
>
<DialogTitle>{title}</DialogTitle>
<DialogContent>
<DialogContentText>{content} </DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={handleConfirm} color="primary">
{confirmationButtonText}
</Button>
<Button onClick={handleClose} color="primary">
Cancel
</Button>
</DialogActions>
</Dialog>
<Component {...props} showConfirmationDialog={handleShow} />
</>
)
}
return ComponentWithConfirmationDialog
}
export default WithConfirmationDialog