'Warning: A component is changing an uncontrolled input to be controlled
I have a project and this project is in order to run a contracting and construction company, and I have a file, which is the information for each of the company’s invoices, and this file is a set of fields, but I had this error and I did not know the cause or how can I solve it?
index.js:1 Warning: A component is changing an uncontrolled input to be controlled. This is likely caused by the value changing from undefined to a defined value, which should not happen. Decide between using a controlled or uncontrolled input element for the lifetime of the component. More info: https://reactjs.org/link/controlled-components
This file displays a set of fields
import { getInvoice } from "../../store/invoiceSlice";
import { useEffect, useState } from "react";
import { useParams } from "react-router-dom";
import Grid from "@material-ui/core/Grid";
import TextField from "@material-ui/core/TextField";
import moment from "moment";
import { useTheme } from "@material-ui/core/styles";
import InputAdornment from "@material-ui/core/InputAdornment";
import TodayIcon from "@material-ui/icons/Today";
import { makeStyles } from "@material-ui/core/styles";
import { PDFViewer } from "@react-pdf/renderer";
import { Document, Page } from "react-pdf";
const useStyles = makeStyles((theme) => ({
root: {
"& > *": {
margin: theme.spacing(1),
},
},
input: {
display: "none",
},
button: {
margin: theme.spacing(1),
// padding: theme.spacing(4),
},
}));
const InvoiceDetails = () => {
const classes = useStyles();
const theme = useTheme();
const breakpoint = theme.breakpoints.down("sm");
const routeParams = useParams();
const [invoice, setInvoice] = useState([]);
// const defaultLayoutPluginInstance = defaultLayoutPlugin();
useEffect(() => {
getInvoice(routeParams).then((response) => {
setInvoice(response);
});
}, []);
console.log("invoice url: ", invoice?.file?.url);
console.log("invoice tara : ", invoice);
const [numPages, setNumPages] = useState(null);
const [pageNumber, setPageNumber] = useState(1);
const onDocumentLoadSuccess = ({ numPages }) => {
setNumPages(numPages);
};
return (
<>
<Grid container>
<Grid item xs={7} sm={7} style={{ height: "100vh", width: "100vh" }}>
{/* <PDFViewer file={invoice?.file?.url}></PDFViewer> */}
<Document
file={invoice?.file?.url}
onLoadSuccess={onDocumentLoadSuccess}
>
<Page pageNumber={pageNumber} />
</Document>
<p>
Page {pageNumber} of {numPages}
</p>
</Grid>
<Grid item xs={5} sm={5} style={{ padding: "3rem" }}>
<Grid item>
<h1 style={{ fontWeight: "bold" }}>Invoice Details</h1>
</Grid>
<Grid item style={{ marginTop: "3rem", marginBottom: "2rem" }}>
<Grid item style={{ marginBottom: 10 }}>
<h3>From</h3>
</Grid>
<Grid item>
<h3>{invoice?.submittedBy?.name}</h3>
</Grid>
<Grid item>
<h3>{invoice?.submittedBy?.email}</h3>
</Grid>
</Grid>
<Grid item>
<Grid container item direction={breakpoint ? "row" : "column"}>
<Grid
container
item
xs={3}
sm={3}
direction="row"
justifyContent="flex-start"
alignItems="center"
>
<h3>Invoice ID</h3>
</Grid>
<Grid item xs={9} sm={9}>
<TextField
className="mt-8 mb-16"
id="outlined-size-normal"
value={invoice.id}
variant="outlined"
fullWidth
/>
</Grid>
</Grid>
<Grid container item direction={breakpoint ? "row" : "column"}>
<Grid
container
item
xs={3}
sm={3}
direction="row"
justifyContent="flex-start"
alignItems="center"
>
<h3>Issue Date</h3>
</Grid>
<Grid item xs={9} sm={9}>
<TextField
className="mt-8 mb-16"
id="outlined-size-normal"
value={moment(moment.utc(invoice.issueDate).toDate())
.local()
.format("YYYY-MM-DD HH:mm:ss")}
variant="outlined"
InputProps={{
endAdornment: (
<InputAdornment position="start">
<TodayIcon />
</InputAdornment>
),
}}
fullWidth
/>
</Grid>
</Grid>
<Grid container item direction={breakpoint ? "row" : "column"}>
<Grid
container
item
xs={3}
sm={3}
direction="row"
justifyContent="flex-start"
alignItems="center"
>
<h3>Due Date</h3>
</Grid>
<Grid item xs={9} sm={9}>
<TextField
className="mt-8 mb-16"
id="outlined-size-normal"
value={moment(moment.utc(invoice.dueDate).toDate())
.local()
.format("YYYY-MM-DD HH:mm:ss")}
variant="outlined"
InputProps={{
endAdornment: (
<InputAdornment position="start">
<TodayIcon />
</InputAdornment>
),
}}
fullWidth
/>
</Grid>
</Grid>
<Grid container item direction={breakpoint ? "row" : "column"}>
<Grid
container
item
xs={3}
sm={3}
direction="row"
justifyContent="flex-start"
alignItems="center"
>
<h3>Net Amount</h3>
</Grid>
<Grid item xs={9} sm={9}>
<TextField
className="mt-8 mb-16"
id="outlined-size-normal"
value={invoice.netAmount}
variant="outlined"
fullWidth
/>
</Grid>
</Grid>
<Grid container item direction={breakpoint ? "row" : "column"}>
<Grid
container
item
xs={3}
sm={3}
direction="row"
justifyContent="flex-start"
alignItems="center"
>
<h3>Tax Number</h3>
</Grid>
<Grid item xs={9} sm={9}>
<TextField
className="mt-8 mb-16"
id="outlined-size-normal"
value={invoice.taxNumber}
variant="outlined"
fullWidth
/>
</Grid>
</Grid>
<Grid container item direction={breakpoint ? "row" : "column"}>
<Grid
container
item
xs={3}
sm={3}
direction="row"
justifyContent="flex-start"
alignItems="center"
>
<h3>Gross Amount</h3>
</Grid>
<Grid item xs={9} sm={9}>
<TextField
className="mt-8 mb-16"
// label="Size"
id="outlined-size-normal"
value={invoice.grossAmount}
variant="outlined"
fullWidth
/>
</Grid>
</Grid>
</Grid>
</Grid>
</Grid>
</>
);
};
export default InvoiceDetails;
Solution 1:[1]
If you set as undefined the value prop of your components they become uncontrolled. This is an example:
<TextField
className="mt-8 mb-16"
id="outlined-size-normal"
value={invoice.id} // invoice.id is initially undefined
variant="outlined"
fullWidth
/>
Then, once you run the setInvoice() to define those values the components become controlled. What you can do to make them always controlled is to set a proper initial value of the state like this:
const [invoice, setInvoice] = useState({ // Note that the initial value is an object and not an array
id: "",
issueDate: null,
netAmount: 0,
taxNumber: 0,
grossAmount: 0
});
Or alternatively you can do this to each of your components:
<TextField
className="mt-8 mb-16"
id="outlined-size-normal"
value={invoice.id || ""}
variant="outlined"
fullWidth
/>
Solution 2:[2]
I believe it's caused by your invoice starting as []. Therefore, fields like invoice.id will be initially null and when u finally fetch data from API & set data into invoice, invoice.id became not null, hence the statement: This is likely caused by the value changing from undefined to a defined value
To solve the warning, you might have to declare all the properties of the invoice in useState. Eg:
useState({
id: "",
issueDate: "",
dueDate: "",
})
or perhaps, use defaultValue instead of value for the TextFields if u don't intend to control the inputs. What's the difference? with value, you have to supply onChange.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Hakim Abdelcadir |
| Solution 2 | Gabsys |
