我正在尝试遵循https://github.com/reactjs/rfcs/issues/26中的设计模式(请参阅bvaughn的回复)并创建ReactJS可编辑表单,从服务器读取数据,然后在表单字段中显示,允许使用编辑值和然后将这些数据保存回数据库。
我有一些必要的代码:
const mapStateToProps = state => {
return {
invoice: state.invoice,
invoiceReady: state.invoiceReady,
};
};
static getDerivedStateFromProps(nextProps, prevState) {
if (nextProps.match.params.id !== prevState.id) {
return update(
prevState, {
['id']: {$set: nextProps.match.params.id},
['invoiceReady']: {$set: false}
});
} else {
return update(
prevState, {
['invoice']: {$set: nextProps.invoice},
['invoiceReady']: {$set: nextProps.invoiceReady}
});
}
}
handleChange(event) {
const state = update(
this.state, {
invoice: {
[event.target.id]: {$set: event.target.value}
}
}
);
this.setState(state);
}
componentDidMount() {
this.requestInvoice();
}
componentDidUpdate(prevProps, prevState) {
if (!this.state.invoiceReady) {
this.requestInvoice();
}
}
我的JSX代码包含可编辑字段,如:
<input
type="text"
className="form-control"
id="invoiceDate"
value={this.state.invoice.invoiceDate}
onChange={this.handleChange}
/>
所以 - 根据提到的模式,我通过requestInvoice
向服务器发起请求,其他一些组件处理此操作并接收并将发票保存到Redux存储中,这就是为什么这些数据会自动写入的原因进入props.invoice
变量,我正在props.invoice
进一步将this.state.invoice
写入getDerivedStateFromProps
,以进一步本地处理发票数据。在使用表单的工作期间,handleChange
事件被引发,并且在immutability-helper(更新函数)的帮助下,更新的字段被写入新状态并且setState
被调用。
我的问题是,在setState
调用期间,React正在调用getDerivedStateFromProps
,因此props.invoice
会覆盖来自用户的所有更改并将其处理为handleChange:setState
功能。
所以 - 如何解决这个问题:setState
和getDerivedStateFromProps
之间的冲突?
可能有以下几种选择:
props.invoice
移到this.state.invoice
(为什么不呢?)?但另一方面,最好将发票保存到this.state中,并确保在编辑发票期间将所有更改应用于this.state.invoice
。getDerivedStateFromProps
期间执行setState
?也许其他一些设计模式或代码更适合我的ReactJS表单?
我正在使用ReactJ 16.x
答案 0 :(得分:1)
如果您决定使用react-redux for component state management
,那么您应该avoid
使用component internal state
来管理setState
由redux store.
控制的handleChange
否则会导致此类问题以及许多if-else,您可能需要处理它。
考虑你的情景,
在setState
而不是致电dispatch
期间,最好是action
update the state in redux store
至connect
,然后通过handleChange(event) {
const stateData = invoice: {
[event.target.id]: {$set: event.target.value}
};
this.props.callDispatch({'UPDATE_SOME_DATA',stateData})
}
,它会反映到您的组件中你调用API的方式。
reducers
只有事情需要注意,确保dispatch action
仅更新所需的已通过属性数据,并保持API [
{"name":"Adele", "href":"#"},
{"name":"Agnes","href":"#"},
{"name":"Billy","href":"#"},
{"name":"Bob","href":"#"},
{"name":"Calvin","href":"#"},
{"name":"Christina","href":"#"},
{"name":"Cindy","href":"#"}
]
进程更新其他数据。
答案 1 :(得分:0)
我已经得到了以下解决方案 - 在this.state.stateUpdate
变量的帮助下 - 我认为这是我的问题的答案(请评论如果这不是合理而且整洁的解决方案,我可以接受其他答案为好吧,如果有效):
const mapStateToProps = state => {
return {
invoice: state.invoice,
invoiceReady: state.invoiceReady,
stateUpdate: false
};
};
static getDerivedStateFromProps(nextProps, prevState) {
if (prevState.stateUpdate) {
return update(
prevState, {
stateUpdate: {$set: false}
}
)
}
if (nextProps.match.params.id !== prevState.id) {
return update(
prevState, {
['id']: {$set: nextProps.match.params.id},
['invoiceReady']: {$set: false}
});
} else {
return update(
prevState, {
['invoice']: {$set: nextProps.invoice},
['invoiceReady']: {$set: nextProps.invoiceReady}
});
}
}
handleChange(event) {
const state = update(
this.state, {
invoice: {
[event.target.id]: {$set: event.target.value}
},
stateUpdate: {$set: true}
}
);
this.setState(state);
}
componentDidMount() {
this.requestInvoice();
}
componentDidUpdate(prevProps, prevState) {
if (!this.state.invoiceReady) {
this.requestInvoice();
}
}