This is the code I have and I still don't know how to use life cycles properly, but the error in the console suggests that I use "ComponentWillUnmount" to fix this "memory leak", but I don't know how to do it, what I have tried so far has not It worked, this is the code that generates the performance deterioration, (don't pay attention to the redux part). This is the repo, the branch is "frontend" https://github.com/Ceci007/final-capstone-frontend
import React from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { Link } from 'react-router-dom';
import FormIllness from '../../components/FormIllness/FormIllness';
import {
fetchUserIllness, createIll, deleteIll,
} from '../../actions/illness';
import { loginStatus } from '../../actions/user';
import './Illness.css';
class Illness extends React.Component {
constructor(props) {
super(props);
this.state = {
addForm: false,
editForm: false,
idIll: '0',
};
}
componentDidMount() {
const { user, fetchUserIllness } = this.props;
const ID = user.user.id;
fetchUserIllness(ID);
}
shouldComponentUpdate(nextProps, nextState) {
const { illness } = this.props;
const {
addForm, editForm,
} = this.state;
return illness !== nextProps.illness
|| addForm !== nextState.addForm
|| editForm !== nextState.editForm;
}
addIllness = (name, description) => {
const { createIll, user } = this.props;
const { addForm } = this.state;
const userId = user.user.id;
createIll({ name, description, userId });
this.setState({
addForm: !addForm,
});
};
displayForm = () => {
const { addForm } = this.state;
this.setState({
addForm: !addForm,
});
}
displayEdit= e => {
const { editForm } = this.state;
this.setState({
editForm: !editForm,
idIll: e.target.id,
});
}
deleteIll = id => {
const { user } = this.props;
const { deleteIll } = this.props;
const userId = user.user.id;
deleteIll({ userId, id });
}
changeEditForm = () => {
const { editForm } = this.state;
this.setState({
editForm: !editForm,
});
}
changeAddForm = () => {
const { addForm } = this.state;
this.setState({
addForm: !addForm,
});
}
render() {
const { illness } = this.props;
const {
addForm, editForm, idIll,
} = this.state;
return (
<main className="main">
<button type="button" className="add-ill" onClick={this.displayForm}>+</button>
<div className="illnesses">
{ !editForm && !addForm && <h3>Your Illnesses</h3>}
{illness.length === 0 && !addForm && <div className="tracking">Start adding a illness you want to track here!</div>}
{illness.map(ill => (
<div key={ill.id}>
{ !editForm && !addForm && (
<div className="one-ill">
<div className="buttons">
<button type="button" onClick={() => this.deleteIll(ill.id)}>
<i className="fa fa-trash-o" />
</button>
<button type="button" onClick={this.displayEdit}>
<i className="fa fa-pencil-square-o" id={ill.id} />
</button>
</div>
<div className="ill-info">
<Link to={{
pathname: `illness/${ill.id}`,
state: {
nameill: ill.name,
},
}}
>
{!editForm && (
<div>
<div className="ill-name">
<p>Name:</p>
<p>Description:</p>
</div>
<div className="ill-description">
<p>{ill.name}</p>
<p>{ill.description}</p>
</div>
</div>
)}
</Link>
</div>
</div>
)}
{ editForm && ill.id.toString() === idIll && <FormIllness actionToPerform="Save Changes" buttonId={idIll} changeEditForm={this.changeEditForm} />}
</div>
))}
</div>
<div className="newill">
{addForm && <FormIllness addIllness={this.addIllness} actionToPerform="Add" changeAddForm={this.changeAddForm} />}
</div>
</main>
);
}
}
const mapStateToProps = state => (
{
user: state.user,
isLogin: state.user.isLogin,
illness: state.illness,
});
const mapDispatchToProps = dispatch => ({
fetchUserIllness: data => dispatch(fetchUserIllness(data)),
createIll: data => dispatch(createIll(data)),
deleteIll: id => dispatch(deleteIll(id)),
loginStatus: () => dispatch(loginStatus()),
});
Illness.propTypes = {
fetchUserIllness: PropTypes.func,
createIll: PropTypes.func,
deleteIll: PropTypes.func,
user: PropTypes.shape({
user: PropTypes.shape({
id: PropTypes.number,
}),
}),
illness: PropTypes.arrayOf(PropTypes.shape({
description: PropTypes.string,
name: PropTypes.string,
})),
};
Illness.defaultProps = {
createIll: () => {},
deleteIll: () => {},
fetchUserIllness: () => {},
illness: {},
user: {},
};
export default connect(mapStateToProps, mapDispatchToProps)(Illness);
This is the form
import React from 'react';
import PropTypes from 'prop-types';
import './FormIllness.css';
import { connect } from 'react-redux';
import { updateIll } from '../../actions/illness';
class FormIllness extends React.Component {
constructor(props) {
super(props);
this.state = {
name: '',
description: '',
};
}
componentDidMount = () => {
const { actionToPerform, buttonId, illness } = this.props;
if (actionToPerform === 'Save Changes') {
const ill = illness.filter(x => x.id.toString() === buttonId);
this.setState({
name: ill[0].name,
description: ill[0].description,
});
}
}
handleChangeName = e => {
this.setState({
name: e.target.value,
});
}
handleChangeDescription = e => {
this.setState({
description: e.target.value,
});
}
handleSubmit = (name, description) => {
const { addIllness } = this.props;
addIllness(name, description);
}
handleUpdate = async id => {
const { name, description } = this.state;
const {
user, updateIll, changeEditForm,
} = this.props;
const data = {
id,
user_id: user.user.id,
name,
description,
};
await updateIll(data);
changeEditForm();
}
render() {
const { name, description } = this.state;
const {
actionToPerform, illness, buttonId, changeEditForm, changeAddForm,
} = this.props;
const ill = illness.filter(x => x.id.toString() === buttonId);
return (
<div>
<h3>
{actionToPerform}
{' '}
Illness
</h3>
<form
className="one-form"
onSubmit={
actionToPerform === 'Add'
? () => this.handleSubmit(name, description) : () => this.handleUpdate(ill[0].id)
}
>
<div className="one-parameter">
<label htmlFor="name">
Name:
<input
required
id="name"
type="text"
name="name"
defaultValue={buttonId === '0' ? name : ill[0].name}
onChange={this.handleChangeName}
/>
</label>
</div>
<div className="one-parameter">
<label htmlFor="description">
Description:
<textarea
id="description"
name="description"
defaultValue={buttonId === '0' ? description : ill[0].description}
onChange={this.handleChangeDescription}
/>
</label>
</div>
<div className="buttons-form">
{actionToPerform === 'Add' && <button type="submit">{actionToPerform}</button>}
{actionToPerform === 'Save Changes' && <button type="submit">Save</button>}
{actionToPerform === 'Add' && <button type="button" onClick={changeAddForm}>Cancel</button>}
{actionToPerform === 'Save Changes' && <button type="button" onClick={changeEditForm}>Cancel</button>}
</div>
</form>
</div>
);
}
}
FormIllness.propTypes = {
addIllness: PropTypes.func,
actionToPerform: PropTypes.string,
changeAddForm: PropTypes.func,
illness: PropTypes.instanceOf(Array),
buttonId: PropTypes.string,
updateIll: PropTypes.func,
changeEditForm: PropTypes.func,
user: PropTypes.shape({
user: PropTypes.shape({
id: PropTypes.number,
}),
}),
};
FormIllness.defaultProps = {
changeAddForm: () => {},
addIllness: () => {},
actionToPerform: '',
illness: [],
buttonId: '0',
updateIll: () => {},
changeEditForm: () => {},
user: {},
};
const mapStateToProps = state => ({
user: state.user,
illness: state.illness,
});
const mapDispatchToProps = dispatch => ({
updateIll: data => dispatch(updateIll(data)),
});
export default connect(mapStateToProps, mapDispatchToProps)(FormIllness);
In-branch: front-end
In file: src/containers/Login/index.js
In line 55 of the handleErrors function:
If you comment that line you wouldn't be making a call from an unmounted component.
After the three-second delay of that function, the Login component is already unmounted. That's the cause of the error.
Happy coding!
}