简体   繁体   English

正在编辑Redux状态而不发送任何操作

[英]Redux state is being edited without dispatching any action

I have an app with react + redux, and the problem is happening in the editing form. 我有一个带有react + redux的应用程序,问题出现在编辑表单中。

Description of the issue 问题说明

  1. click "edit" to edit a document 单击“编辑”以编辑文档
  2. Show the edit form 显示编辑表单
  3. I edit/delete one of the values 我编辑/删除其中一个值
  4. instead of saving (dispatching an action to save) I return to any other page without saving 而不是保存(调度要保存的操作)我返回到任何其他页面而不保存
  5. then comeback to the description page for this object (where the "edit" button is located) 然后回到此对象的描述页面(“编辑”按钮所在的位置)

Result 结果

The document is edited. 文档已编辑。

So, from the Portlets component, when I click on the edit button, I'll setState({isEditing: true}) : 因此,从Portlets组件中,当我单击编辑按钮时,我将设置setState({isEditing: true})

if(this.state.isEditing) {
  return (
    <div className="col-md-12">
      <div className="card">
        <div className="card-content">
          <PortletForm />
        </div>
      </div>
    </div>
  );

Then I open the <PortletForm /> component, and access again the data with connect() : 然后我打开<PortletForm />组件,并使用connect()再次访问数据:

function mapStateToProps(state, ownProps) {
  let portlet = {};

  const portletId = ownProps.match.params.id;

  if (state.portlets.length > 0) {
    portlet = Object.assign({}, state.portlets.find(portlet => portlet._id === portletId));
  }

  return { portlet: portlet };
}

function mapDispatchToProps(dispatch) {
  return {
    actions: bindActionCreators(portletActions, dispatch)
  };
}

export default withRouter(connect(mapStateToProps, mapDispatchToProps)(PortletForm));

This is the constructor() in the editing form: 这是编辑表单中的constructor()

constructor(props) {
    super(props);

    this.state = {
      portlet: this.props.portlet,
      addNewKey: [],
      addNewKeyDisabled: false,
      newKey: '',
      newValue: ''
    };

    ...
}

This is the <input /> in jsx where that calls the editing function: 这是jsx中的<input /> ,它调用编辑功能:

<input
  type="text"
  className="form-control"
  autoFocus={index === 0}
  name={Object.keys(key)}
  value={Object.values(key)}
  onChange={this._updatePortletKey} /> 

and _updatePortletKey() , where the problem seems to be happening: _updatePortletKey() ,问题似乎发生在:

_updatePortletKey(event) {
    const field = event.target.name;
    let editedDoc = Object.assign({}, this.state.portlet);
    editedDoc._keys.map((elem, index) => {
      const key = Object.keys(editedDoc._keys[index]);
      if(key[0] === field) {
        return editedDoc._keys[index][field] = event.target.value;
      }
    });
    debugger;
    this.setState({ portlet: editedDoc });
  }

So I create a new object, and assign it modified to the state, after some debuggin this is what I found: 所以我创建了一个新对象,并将其修改为状态,经过一些调试后,这就是我发现的:

  • When I'm accessing this function this.props.portlet contains the original object 当我访问此函数时, this.props.portlet包含原始对象
  • Right after I return the new keys from the map function (where the debugger is placed) and before I edit the state, this.props.portlet contains the edited key! 在我从map函数(放置调试器的位置)返回新键之后,在编辑状态之前, this.props.portlet 包含已编辑的键! .

I really don't know what else to try, before this function I'm not triggering any dispatch or somethig, but I also tried a console.log() inside mapStateToProps() and after coming back to the non saved document the store is edited , I don't get it! 我真的不知道还有什么可以尝试,在这个函数之前我没有触发任何调度或者somethig,但是我也在mapStateToProps()尝试了一个console.log() mapStateToProps()并且在回到未保存的文档后,商店是编辑 ,我不明白! I also checked that the parent function does not contain any other function that might be working at the same time... got nothing. 我还检查了父函数不包含任何可能同时工作的其他函数......什么也没得到。

Any help is appreciated. 任何帮助表示赞赏。 Thanks in advance! 提前致谢!

Edit: this is how this.props.portlet looks like: 编辑:这就是this.props.portlet样子:

{
    country: "AR"
    dev: true
    slug: "document-name"
    test: false
    version: 2
    _id: "5a798e53f2c5340bb08479f8"
    _keys: [
        { newKey: "new key value" }
    ]
}

This is why suggested method to deal with redux is ImmutableJS or immutable-helper or the kind. 这就是为什么建议的处理redux的方法是ImmutableJSimmutable-helper或者那种。

It is very easy to make mistakes otherwise. 否则很容易犯错误。

Here is what happend: 这是发生的事情:

// constructor
this.state = {
  portlet: this.props.portlet,  // you put props in the state
}

// change handler
let editedDoc = Object.assign({}, this.state.portlet);
// here a new object is created, but if the value is not primitive, it is by reference.
// this means, while editedDoc and this.state.portlet are different objects, "_key"'s value is shared between these object.

And this is a mistake I have seen many people making. 这是我见过许多人制作的错误。 Also, it is a pain to debug such cases. 此外,调试此类案件也很痛苦。 So please use a helper library. 所以请使用帮助程序库。

If you insist on using es6 to construct new object, it could get ugly as the nesting increases. 如果你坚持使用es6来构造新对象,那么随着嵌套的增加,它可能变得丑陋。

// example 1
_updatePortletKey(event) {
  const field = event.target.name;

  this.setState({
    portlet: {
      ...this.state.portlet,
      _keys: this.state.portlet._keys.reduce((agg, el) => {
        const key = Object.keys(el); 
        // btw, what are you trying to do here !! (my logic might be slightly off, as I didn't fully understood the transformation, but you get the idea, right?)
        if(key[0] === field) { 
          return [...agg, {...el, [field]: event.target.value}]
        }
        return [...agg,el]
      }, [])
    }
  })

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

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