正在编辑 Redux 状态,而无需调度任何操作 [英] Redux state is being edited without dispatching any action

查看:44
本文介绍了正在编辑 Redux 状态,而无需调度任何操作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个带有 react + redux 的应用,问题出在编辑表单中.

问题描述

  1. 点击编辑"以编辑文档
  2. 显示编辑表单
  3. 我编辑/删除了其中一个值
  4. 我没有保存(发送一个操作来保存)而是返回到任何其他页面不保存
  5. 然后返回到此对象的描述页面(编辑"按钮所在的位置)

结果

文档已编辑.

因此,从 Portlets 组件中,当我单击编辑按钮时,我将 setState({isEditing: true}):

if(this.state.isEditing) {返回 (<div className="col-md-12"><div className="card"><div className="卡片内容"><PortletForm/>

);

然后我打开 <PortletForm/> 组件,并再次使用 connect() 访问数据:

function mapStateToProps(state, ownProps) {让 portlet = {};const portletId = ownProps.match.params.id;如果(state.portlets.length > 0){portlet = Object.assign({}, state.portlets.find(portlet => portlet._id === portletId));}返回 { portlet: portlet };}函数 mapDispatchToProps(dispatch) {返回 {动作:bindActionCreators(portletActions, dispatch)};}导出默认 withRouter(connect(mapStateToProps, mapDispatchToProps)(PortletForm));

这是编辑表单中的constructor():

构造函数(道具){超级(道具);this.state = {portlet: this.props.portlet,addNewKey: [],addNewKeyDisabled: 假,新键:'',新值:''};...}

这是jsx中调用编辑功能的:

<输入类型=文本"className="表单控件"自动对焦={索引=== 0}名称={Object.keys(key)}值={Object.values(key)}onChange={this._updatePortletKey}/>

_updatePortletKey(),问题似乎发生在:

_updatePortletKey(event) {const 字段 = event.target.name;让editedDoc = Object.assign({}, this.state.portlet);editedDoc._keys.map((elem, index) => {const key = Object.keys(editedDoc._keys[index]);如果(键 [0] === 字段){返回editedDoc._keys[index][field] = event.target.value;}});调试器;this.setState({ portlet:editedDoc });}

所以我创建了一个新对象,并将其分配给状态,经过一些调试后,我发现:

  • 当我访问这个函数时 this.props.portlet 包含原始对象
  • 在我从地图函数(放置调试器的地方)返回新键之后和编辑状态之前,this.props.portlet 包含编辑的键!.

我真的不知道还能尝试什么,在这个函数之前我没有触发任何调度或其他东西,但我也在 mapStateToProps() 中尝试了一个 console.log()) 回到未保存的文档后,商店被编辑,我不明白!我还检查了父函数不包含任何其他可能同时工作的函数......一无所获.

感谢任何帮助.提前致谢!

这是 this.props.portlet 的样子:

<代码>{国家:AR"开发:真的slug:文件名"测试:假版本:2_id:5a798e53f2c5340bb08479f8"_keys: [{ newKey: "新键值" }]}

解决方案

这就是为什么建议的处理 redux 的方法是 ImmutableJSimmutable-helper 或那种.

否则很容易犯错误.

这是发生了什么:

//构造函数this.state = {portlet: this.props.portlet,//你把 props 放在 state 中}//更改处理程序让editedDoc = Object.assign({}, this.state.portlet);//这里创建了一个新对象,但如果值不是原始值,则是通过引用.//这意味着,editedDoc 和 this.state.portlet 是不同的对象,_key"的值在这些对象之间共享.

这是我见过很多人犯的错误.此外,调试此类情况也很痛苦.所以请使用辅助库.

如果你坚持使用 es6 来构造新对象,随着嵌套的增加,它可能会变得丑陋.

//示例 1_updatePortletKey(事件){const 字段 = event.target.name;this.setState({门户:{...this.state.portlet,_keys: this.state.portlet._keys.reduce((agg, el) => {const key = Object.keys(el);//顺便说一句,你在这里想做什么!!(我的逻辑可能有点偏离,因为我没有完全理解转换,但你明白了,对吧?)如果(键 [0] === 字段){返回 [...agg, {...el, [field]: event.target.value}]}返回 [...agg,el]}, [])}})

I have an app with react + redux, and the problem is happening in the editing form.

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}):

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():

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(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:

<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(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
  • 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!.

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! 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:

{
    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.

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.

// 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]
      }, [])
    }
  })

这篇关于正在编辑 Redux 状态,而无需调度任何操作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆