Reputation: 23
First of all this is a simplified example: Codepen Project
I am building an edit form in react, which checks if there are any changes. You can only save the form if there are any changes and any changes you made will be shown by changing the style (border-left) on the matching input element. It looks like this
To do that I am saving the original data/ state in the component state in the componentDidMount method and compare that to the state of the different inputs.
componentDidMount() {
// if the project is accessed from home and is not a new project, project data will be passed along
if (this.props.project) {
this.setState({
name: this.props.project.name,
tags: this.props.project.tags
}, this.setInitialState)
} else if (this.props.edit && this.props.match.params.id) {
// instead of an api call to get project data, if the project is accessed directly by url
const project = projects.find((project) => project.name === this.props.match.params.id)
this.setState({
name: project.name,
tags: project.tags
}, this.setInitialState)
}
// if there are no project data or an edit prop, it's a new project and the initialState remains empty
}
On each Input Change the input Value is compared to the initialState:
compareInputData() {
const formFields = {
name: {
ref : this.name,
changed : false
},
tags: {
ref : this.tagList,
changed : false
}
}
const state = this.state
const first = this.state.initialState
const nameHasChanged = state.name !== first.name
const tagsHaveChanged = state.tags.length !== first.tags.length
nameHasChanged
? ( formFields.name.changed = true )
: ( formFields.name.changed = false )
tagsHaveChanged
? ( formFields.tags.changed = true )
: ( formFields.tags.changed = false )
nameHasChanged || tagsHaveChanged
? (this.setState({
isChanged: true
}))
: (this.setState({
isChanged: false
}))
this.handleChangedInputStyles(formFields)
}
If there are changes the styling of the matching element is changed:
handleChangedInputStyles(formFields) {
const formFieldKeys = Object.keys(formFields)
formFieldKeys.map(key => {
formFields[key].changed
? formFields[key].ref.style.borderLeft = `2px solid orange`
: formFields[key].ref.style.borderLeft = '1px solid black'
})
}
That is working the way I want it to on normal input fields, but I am also saving related tags as an array, which are displayed as a list. Whenever I update that list (this.state.tags) my original state for the tags is being updated as well (this.state.initialState.tags), which means that I cannot pick up changes in my tag List. However it does work if I am creating adding a tag to a new project instead of editing an existing one... I have no idea how to fix that issue, since I don't really know what's causing it and I would love some help.
Thank you for reading through this post :)
Upvotes: 2
Views: 157
Reputation: 7344
Do not store this.state.initialState
in the state. Store it in a member instead. For instance:
constructor(props) {
this.initialState = Object.assign({}, whatever...);
this.initialState.tags = [].concat(this.initialState.tags); // Keep a shallow copy of this array.
}
Note: Internally, React may modify the tags
array. If you keep a copy, that copy will not be modified.
Upvotes: 1