简体   繁体   English

反应形式的无意状态更新

[英]unintentional state update in react form

First of all this is a simplified example: Codepen Project首先这是一个简化的例子: Codepen Project

I am building an edit form in react, which checks if there are any changes.我正在 React 中构建一个编辑表单,它检查是否有任何更改。 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 方法的组件状态中,并将其与不同输入的状态进行比较。

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:在每个 Input Change 中,将输入 Value 与 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.每当我更新该列表 (this.state.tags) 时,我的标签的原始状态也会更新 (this.state.initialState.tags),这意味着我无法在我的标签列表中获取更改。 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 :)感谢您阅读这篇文章:)

Do not store this.state.initialState in the state.不要在状态中存储this.state.initialState 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.注意:在内部,React 可能会修改tags数组。 If you keep a copy, that copy will not be modified.如果您保留副本,则不会修改该副本。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM