The modal is rendered under the hashRouter in App.js. The modal is shown when its state isOpen is true.
I'm given this error when trying to display a Modal with react redux.
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 ConnectFunction (at Modal.js:41)
in TrapFocus (created by ForwardRef(Modal))
in div (created by ForwardRef(Modal))
in ForwardRef(Portal) (created by ForwardRef(Modal))
in ForwardRef(Modal) (at Modal.js:35)
in Modal (created by ConnectFunction)
in ConnectFunction (created by WithStyles(undefined))
in WithStyles(undefined) (at App.js:46)
in ThemeProvider (at App.js:24)
in App (created by WithStyles(App))
in WithStyles(App) (at src/index.js:13)
in Provider (at src/index.js:12)
This is my code:
Modal.js
import React, { Component } from "react";
import { compose } from "redux";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import { Modal as MaterialModal } from "@material-ui/core";
import { withStyles } from "@material-ui/styles";
import { closeModal } from "../store/actions/actions-ui";
import BasicModal from "./Modals/BasicModal";
const ModalTypes = {
BasicModal,
};
const styles = {
modal: {
display: "flex",
justifyContent: "center",
alignItems: "center",
},
};
class Modal extends Component {
handleCloseModal = () => {
const { dispatch, shouldCloseOnBackgroundTouch } = this.props;
if (shouldCloseOnBackgroundTouch) dispatch(closeModal());
};
render() {
const { modalType, data, isOpen, classes } = this.props;
if (!modalType) {
return null;
}
const ModalToRender = ModalTypes[modalType];
return (
<MaterialModal
disableAutoFocus
className={classes.modal}
open={isOpen}
onClose={this.handleCloseModal}
>
<ModalToRender {...data} />
</MaterialModal>
);
}
}
Modal.propTypes = {
dispatch: PropTypes.func.isRequired,
isOpen: PropTypes.bool.isRequired,
modalType: PropTypes.string,
// eslint-disable-next-line react/forbid-prop-types
data: PropTypes.object,
shouldCloseOnBackgroundTouch: PropTypes.bool.isRequired,
classes: PropTypes.objectOf(PropTypes.string).isRequired,
};
Modal.defaultProps = {
data: {},
modalType: "",
};
const mapStateToProps = (state) => ({
isOpen: state.ui.modalState.isOpen,
shouldCloseOnBackgroundTouch: state.ui.modalState.shouldCloseOnBackgroundTouch,
modalType: state.ui.modalState.modalType,
data: state.ui.modalState.data,
});
export default compose(
withStyles(styles),
connect(mapStateToProps)
)(Modal);
BasicModal.js
import React, { Component } from "react";
import { connect } from "react-redux";
import PropTypes from "prop-types";
import Button from "@material-ui/core/Button";
import Typography from "@material-ui/core/Typography";
import Paper from "@material-ui/core/Paper";
import If from "../__helpers__/If";
import { closeModal } from "../../store/actions/actions-ui";
class BasicModal extends Component {
handleClose = () => {
const { dispatch } = this.props;
dispatch(closeModal());
};
render() {
const { title, text, extraBtnText, extraBtnAction } = this.props;
return (
<Paper>
<If truthy={title}>
<Typography gutterBottom variant="h4">
{title}
</Typography>
</If>
<If truthy={text}>
<Typography gutterBottom vairant="body2">
{text}
</Typography>
</If>
<Button onClick={this.handleClose}>Close</Button>
<If truthy={extraBtnAction && extraBtnText}>
<Button
onClick={() => {
extraBtnAction();
this.handleClose();
}}
>
{extraBtnText}
</Button>
</If>
</Paper>
);
}
}
BasicModal.propTypes = {
dispatch: PropTypes.func.isRequired,
title: PropTypes.string.isRequired,
text: PropTypes.string.isRequired,
extraBtnText: PropTypes.string,
extraBtnAction: PropTypes.func,
};
export default connect()(BasicModal);
I'm guessing that the issue lies with me trying to render a component like this:
<ModalToRender {...data} />
But I can't seem to understand what is wrong with it.
Any help is appreciated!
You need to use the forwardRef option in connect() for the component (e.g. BasicModal
) that is wrapped by Material-UI's Modal
.
Example:
export default connect(null, null, null, {forwardRef: true})(BasicModal);
Refs provide access to the DOM node for a React element. Material-UI's TrapFocus
(which is used by Modal
) uses a ref on the child passed to Modal
to manage focus aspects.
In your case, the child passed to Modal
is the wrapper component returned by connect()(BasicModal)
. That wrapper component is, by default, a function component and function components cannot accept refs except by being wrapped by forwardRef.
The forwardRef
option of connect
causes it to wrap the function component using React.forwardRef
so that it can successfully accept a ref which it passes along to the wrapped component (BasicModal
in your case).
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