I am relatively beginner in React, and in this particular situation, I am probably missing something very fundamental.
Here, I have a simple CRUD app, and after user adds new data, the updated list of items should be rendered. And the new data is added with a second Dialog component AddNewDevelopmentWork.js
So, after new data is added by the AddNewDevelopmentWork.js (which is the child compoenent that will only open a dialog for the user to input and fill few TestFields), in the main component (DevelopmentList.js), I am using componentDidUpdate to do the comparison with current state and prevState (for the state variable allDevelopmentWorks which is an array of objects) , and if they are not equal then make a request to the backend Express API and fetchin data and updating state within componentDidUpdate. And then render with new data.
Problem is, this main DevelopmentList.js component is not rendering the new data entered by the user till the page is refreshed. But after refreshing the page manually its showing the newly entered data.
Here is my DevelopmentList component.
class DevelopmentList extends Component {
constructor(props) {
super(props);
this.state = {
allDevelopmentWorks: []
};
}
componentDidUpdate(prevProps, prevState) {
if (
this.state.allDevelopmentWorks.length !==
prevState.allDevelopmentWorks.length
) {
return axios
.get("/api/developmenties")
.then(res => {
this.setState({
allDevelopmentWorks: res.data
});
})
.catch(function(error) {
console.log(error);
});
}
}
componentDidMount() {
axios.get("/api/developmenties").then(res => {
this.setState({
allDevelopmentWorks: res.data
});
});
}
render() {
const { classes } = this.props;
return (
<div>
<Table className={classes.table}>
<TableHead>
<TableRow className={classes.row}>
<CustomTableCell align="left">Location</CustomTableCell>
<CustomTableCell align="left">
Description Of Work
</CustomTableCell>
<CustomTableCell align="left">
Date of Commencement
</CustomTableCell>
<CustomTableCell align="left">Date of Completion</CustomTableCell>
<CustomTableCell align="left">Status of Work</CustomTableCell>
</TableRow>
</TableHead>
<TableBody>
{this.state.allDevelopmentWorks.map((document, i) => (
<TableRow className={classes.row} key={i}>
<CustomTableCell component="th" scope="row">
{document.location}
</CustomTableCell>
<CustomTableCell align="left">
{document.work_description}
</CustomTableCell>
<CustomTableCell align="left">
{moment(document.date_of_commencement).format("YYYY-MM-DD")}
</CustomTableCell>
<CustomTableCell align="left">
{moment(document.date_of_completion).format("YYYY-MM-DD")}
</CustomTableCell>
<CustomTableCell align="left">
{document.status_of_work}
</CustomTableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
);
}
}
export default withStyles(styles)(DevelopmentList);
However, withing the componentDidUpdate method below, if I change it to as below the if condition (taking the length propery out of equation) then the new data is immediately rendered on the page, but then it also becomes an infinite loop inside componentDidUpdate and hitting the Express API again and again each second.
componentDidUpdate(prevProps, prevState) {
if (
this.state.allDevelopmentWorks !==
prevState.allDevelopmentWorks
) {
return axios
.get("/api/developmenties")
.then(res => {
this.setState({
allDevelopmentWorks: res.data
});
})
.catch(function(error) {
console.log(error);
});
}
}
The code in the second component, (which is the child component to the main DevelopmentList.jscomponent, that will only open a dialog for the user to input and fill few TestFields add new data to this CRUD) is below AddNewDevelopmentWork.js
class AddNewDevelopmentWork extends Component {
state = {
open: false,
location: "",
work_description: "",
date_of_commencement: new Date(),
date_of_completion: new Date(),
status_of_work: "",
vertical: "top",
horizontal: "center"
};
handleCommencementDateChange = date => {
this.setState({
date_of_commencement: date
});
};
handleCompletionDateChange = date => {
this.setState({
date_of_completion: date
});
};
handleToggle = () => {
this.setState({
open: !this.state.open
});
};
handleClickOpen = () => {
this.setState({ open: true });
};
handleClose = () => {
this.props.history.push("/dashboard/developmentworks");
};
onChange = e => {
const state = this.state;
state[e.target.name] = e.target.value;
this.setState(state);
};
handleFormSubmit = e => {
e.preventDefault();
const {
location,
work_description,
date_of_commencement,
date_of_completion,
status_of_work
} = this.state;
axios
.post("/api/developmenties/", {
location,
work_description,
date_of_commencement,
date_of_completion,
status_of_work
})
.then(() => {
// this.props.history.push("/dashboard/developmentworks");
// window.location.href = window.location.href;
this.setState({
open: false,
vertical: "top",
horizontal: "center"
});
})
.catch(error => {
alert("Ooops something wrong happened, please try again");
});
};
handleCancel = () => {
this.setState({ open: false });
};
render() {
const { classes } = this.props;
const {
location,
work_description,
date_of_commencement,
date_of_completion,
status_of_work,
vertical,
horizontal
} = this.state;
return (
<MuiThemeProvider theme={theme}>
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<div>
<MuiThemeProvider theme={theme}>
<Dialog open={this.state.open} onClose={this.handleToggle}>
<DialogContent required>
<form onSubmit={this.handleFormSubmit}>
<TextField
value={location}
onChange={e =>
this.setState({
location: e.target.value
})
}
error={location === ""}
helperText={
location === "" ? "Please enter Location" : " "
}
label="Location"
type="email"
fullWidth
/>
<TextField
value={work_description}
onChange={e =>
this.setState({
work_description: e.target.value
})
}
error={work_description === ""}
helperText={
work_description === ""
? "Please enter Work Description"
: " "
}
label="Description of Work"
type="email"
fullWidth
/>
<div>
<DatePicker
format="dd/MM/yyyy"
label="Date of Commencement"
value={date_of_commencement}
onChange={this.handleCommencementDateChange}
disableOpenOnEnter
animateYearScrolling={false}
/>
</div>
<div>
<DatePicker
format="dd/MM/yyyy"
label="Date of Completion"
value={date_of_completion}
onChange={this.handleCompletionDateChange}
/>
</div>
<TextField
value={status_of_work}
onChange={e =>
this.setState({
status_of_work: e.target.value
})
}
error={location === ""}
helperText={
status_of_work === ""
? "Please enter Status of Work!"
: " "
}
label="Status of Work"
type="email"
fullWidth
/>
</form>
</DialogContent>
<DialogActions>
<Button
onClick={this.handleCancel}
classes={{
root: classes.root
}}
variant="contained"
>
Cancel
</Button>
<Button
onClick={this.handleFormSubmit}
color="primary"
variant="contained"
>
Save
</Button>
</DialogActions>
</Dialog>
</MuiThemeProvider>
</div>
</MuiPickersUtilsProvider>
</MuiThemeProvider>
);
}
}