我正在尝试使用由于我们使用jQuery UI DatePicker和jQuery maskMoney而不受控制的表单输入元素,并且一旦用户键入对该字段无效的内容,它们也会在其下方显示错误作为禁用任何错误的按钮。由于某些原因,none of that is working right。
主要组件
类似于以下内容:
class MainComponent extends React.Component {
constructor(props) {
super(props)
this.state = {
payrates: [
new PayRate(new Date(2019, 2, 1), 0.00),
],
errors : {
rate: '',
date: ''
},
currentPayRate : new PayRate() // has Rate and EffectiveDate fields
}
// binding done here
this.appendValue = this.appendValue.bind(this)
this.updateCurrentPayRate = this.updateCurrentPayRate.bind(this)
this.updateCurrentPayRateDate = this.updateCurrentPayRateDate.bind(this)
this.updateCurrentPayRateAmount = this.updateCurrentPayRateAmount.bind(this)
this.validate = this.validate.bind(this)
}
/**
* @param { PayRate } newPayRate
**/
updateCurrentPayRate(newPayRate) {
this.setState({
...this.state,
currentPayRate : newPayRate
})
}
updateCurrentPayRateDate(dateString) {
const newPayRate = Object.assign(new PayRate(), this.state.currentPayRate, { EffectiveDate : new Date(dateString) } )
this.validate(newPayRate)
this.updateCurrentPayRate(newPayRate)
}
updateCurrentPayRateAmount(amount) {
const newPayRate = Object.assign(new PayRate(), this.state.currentPayRate, { Rate : Number(amount) } )
this.validate(newPayRate)
this.updateCurrentPayRate(newPayRate)
}
/**
* @param { PayRate } value
**/
appendValue(value) {
console.log("trying to append value: ", value)
if (this.validate(value)) {
this.setState({...this.state,
payrates : this.state.payrates.concat(this.state.currentPayRate)})
}
}
/**
* @param { PayRate } value
**/
validate(value) {
// extract rate,date from value
const rate = value.Rate,
date = value.EffectiveDate
console.log("value == ", value)
let errors = {}
// rate better resolve to something
if (!rate) {
errors.rate = "Enter a valid pay rate amount"
}
// date better be valid
if ((!date) || (!date.toLocaleDateString)) {
errors.date = "Enter a date"
}
else if (date.toLocaleDateString("en-US") === "Invalid Date") {
errors.date = "Enter a valid pay rate date"
}
console.log(errors)
// update the state with the errors
this.setState({
...this.state,
errors : errors
})
const errorsToArray = Object.values(errors).filter((error) => error)
return !errorsToArray.length;
}
render() {
return <div>
<DateList dates={this.state.payrates}/>
<NewPayRateRow
value={this.state.currentPayRate}
errors={this.state.errors}
onChange={this.updateCurrentPayRate}
onPayRateAmountChange={this.updateCurrentPayRateAmount}
onPayRateDateChange={this.updateCurrentPayRateDate}
onAdd={this.appendValue}
/>
</div>
}
}
“表单”组件
具有以下实现:
class NewPayRateRow extends React.Component {
constructor(props) {
super(props)
}
render() {
console.log(Object.values(this.props.errors).filter((error) => error))
return <span class="form-inline">
<RateField
errors={this.props.errors.rate}
onKeyUp={(e) => {
// extract the value
const value = e.target.value
this.props.onPayRateAmountChange(value)
}}
/>
<DateInput
errors={this.props.errors.date}
onChange={this.props.onPayRateDateChange}
/>
<button onClick={(e) => {
this.props.onAdd(this.props.value)
}}
disabled={Object.values(this.props.errors).filter((error) => error).length}>Add New Pay Rate</button>
</span>
}
}
不受控制的输入组件
肯定发生问题的地方:
class DateInput extends React.Component {
constructor(props) {
super(props);
// do bindings
this.handleChange = this.handleChange.bind(this);
}
componentDidMount() {
$('#datepicker').datepicker({
changeMonth: true,
changeYear: true,
showButtonPanel: true,
yearRange: "-116:+34",
dateFormat: 'mm/dd/yy',
// telling jQuery UI to pass its event to React
onSelect : this.handleChange
});
}
componentWillUnmount() {
$('#datepicker').datepicker('destroy')
}
// handles a change to the input field
handleChange(value) {
this.props.onChange(value)
}
render() {
const fieldIsInvalid = this.props.errors || ''
return <div class="col-md-2">
<input
id="datepicker"
className={"datepicker form-control " + fieldIsInvalid }
placeholder="mm/dd/yyyy"
onChange={(e) => this.props.onChange(e.target.value) }>
</input>
<div>
{this.props.errors}
</div>
</div>
}
}
由于某些原因,即使我通过datepicker窗口小部件选择值,errors
也不会改变:
但是,当我注释掉所有validate
调用时,它毫无问题地添加了字段。
我在传递给value
的{{1}}上做了一些穴居调试,以确保传递真实数据。
为什么validate
不能通过组件正确更新?!
更新:我最初只是更新工资率,并正确显示了错误,并且通过检查代码,我发现this.state.error
实际上是在设置状态。但是,当我去触发输入金额字段上的更改时,this.setState
被击中,并且this.setState
对象为空(这是正确的),但是以某种方式,errors
不是实际更新状态。
答案 0 :(得分:3)
我已解决问题!
我做什么
我没有将errors
保留在全局state
中,而是将其设置为在主要组件外部定义的函数,而不是将validate
传递给方法来设置全局状态,而是将其设置为方法课,像这样:
/**
* Validates a PayRate
* @param { PayRate } value
* @returns { Object } any errors
**/
function validate(value = {}) {
// extract rate,date from value
const rate = value.Rate,
date = value.EffectiveDate
let errors = {}
// rate better resolve to something
if (!rate) {
errors.rate = "Enter a valid pay rate amount"
}
// date better be valid
if ((!date) || (!date.toLocaleDateString)) {
errors.date = "Enter a date"
}
else if (date.toLocaleDateString("en-US") === "Invalid Date") {
errors.date = "Enter a valid pay rate date"
}
return errors
}
请注意更简单的实现。然后,我不再需要在validate
方法上调用updateCurrentPayRate...
。
相反,我在NewPayRateRow.render
上调用它(现在可以执行此操作,因为它完全不接触状态,避免了任何不变的违反),将结果保存到名为errors
的本地const变量中,并使用它代替this.props.errors
。虽然,说实话,我可能可以将validate
放回this.props
中以实现抽象/可扩展性层。
此外,我接受了Pagoaga的建议,并使用className
代替了class
(我还没有用它作为肌肉记忆)。
答案 1 :(得分:2)
您的几个渲染函数中都有一个“ class”属性,将其替换为“ className”将显示错误:https://codepen.io/BPagoaga/pen/QoMXmw
return <div className="col-md-2">