正在编辑 Redux 状态,而无需调度任何操作 [英] Redux state is being edited without dispatching any action
问题描述
我有一个带有 react + redux 的应用,问题出在编辑表单中.
问题描述
- 点击编辑"以编辑文档
- 显示编辑表单
- 我编辑/删除了其中一个值
- 我没有保存(发送一个操作来保存)而是返回到任何其他页面不保存
- 然后返回到此对象的描述页面(编辑"按钮所在的位置)
结果
文档已编辑.
因此,从 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 的方法是 ImmutableJS
或 immutable-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
- click "edit" to edit a document
- Show the edit form
- I edit/delete one of the values
- instead of saving (dispatching an action to save) I return to any other page without saving
- 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屋!