我试图通过编写一个React组件来处理页面中容易出错的部分,从而使用ReactJS来修复完全在jQuery中实现的页面。该页面是一个“编辑任务”页面,其中包含多个部分,其中一个部分称为“薪资”部分
页面状态可以这样描述:
它包含TaskObject
个集合,每个集合具有Payrates
和Permissions
。
我正在尝试传递Payrates
,这当然会随着单击另一个任务(另一个TaskObject
的UI元素而改变)。
要开始滚动,我制作了一个存根pageState
,它在全局范围内声明,具有以下实现:
function createPageState() {
let _currentTaskObject;
return {
getCurrentTaskObject : () => _currentTaskObject,
setCurrentTaskObject : (taskObject) => _currentTaskObject = taskObject,
getTaskPayRates : () => {
if (_currentTaskObject) {
return _currentTaskObject.Payrates
}
return [];
}
}
}
let pageState = createPageState()
点击任务后,pageState.setCurrentTaskObject
被调用。
React主要组件具有以下实现:
class PayRatesContainerComponent extends React.Component {
constructor(props) {
super(props)
const payRates = (typeof props.payRates === 'function') ? props.payRates() : props.payRates
this.state = {
payRates : payRates,
errors : {
rate : '',
date : ''
},
currentPayRate : new PayRate(-1, -1, -1, null),
selectedPayRateIndex : -1,
payRateIndicesToDelete : [],
dateString : ''
}
// binding done here; // TODO: look into an auto-binding third-party library to automate all this
this.updateCurrentPayRate = this.updateCurrentPayRate.bind(this)
this.updateCurrentPayRateDate = this.updateCurrentPayRateDate.bind(this)
this.updateCurrentPayRateAmount = this.updateCurrentPayRateAmount.bind(this)
this.updateSelectedPayRateIndex = this.updateSelectedPayRateIndex.bind(this)
this.updatePayRateAt = this.updatePayRateAt.bind(this)
this.checkForDuplicates = this.checkForDuplicates.bind(this)
}
// setup logic
componentDidMount() {
}
// teardown logic
componentWillUnmount() {
}
// business logic
/**
* @param { PayRate } newPayRate
**/
updateCurrentPayRate(newPayRate) {
this.setState({
...this.state,
currentPayRate : newPayRate
})
}
updateCurrentPayRateDate(dateString) {
//
this.setState({
...state,
dateString : dateString
})
const newPayRate = Object.assign(new PayRate(), this.state.currentPayRate, { EffectiveDate : new Date(dateString) } )
this.updateCurrentPayRate(newPayRate)
}
updateCurrentPayRateAmount(amount) {
const newPayRate = Object.assign(new PayRate(), this.state.currentPayRate, { Rate : Number(amount) } )
this.updateCurrentPayRate(newPayRate)
}
updateSelectedPayRateIndex(newIndex = -1) {
const newPayRate = (newIndex === -1) ?
currentPayRate :
this.state.payrates[newIndex]
this.setState({
...this.state,
selectedPayRateIndex : newIndex,
currentPayRate : newPayRate
})
}
updatePayRateAt(index = -1, newPayRate) {
const payRatesCount = this.state.payrates.length;
if ((index >= payRatesCount) || (index < 0)) {
throw RangeError('index must correspond to the list of payrates')
}
if (index === -1) {
this.appendValue(newPayRate)
return;
}
let listOfPayRates = [
...this.state.payrates.slice(0, index),
newPayRate,
...this.state.payrates.slice(index + 1)
]
this.setState({
...this.state,
payrates: listOfPayRates,
...this.blankState
})
}
/**
* Checks for duplicates
* @param { PayRate } newPayRate
* @returns whether or not there's pay rates dated the same as this
*/
checkForDuplicates(newPayRate) {
// if there's no effective date to compare, we're done
if (!newPayRate.EffectiveDate) {
return false;
}
// extract the date from newPayRate
const date = newPayRate.GetReadableDate()
// for all the pay rates on the list
for (let idx in this.state.payrates) {
const payrate = this.state.payrates[idx]
// if we found one whose date matches, we're done here
if ((payrate.GetReadableDate() === date) &&
(this.state.selectedPayRateIndex != idx)
) {
return true;
}
}
return false;
}
// what this Component shall render
render() {
/**
* the actual validator
* @param {{payRate : PayRate, dateString : string}} value
*/
const validator = (value) => {
// check the payRate part
let errors = validate(value.payRate)
// now, check the dateString
if (!value.dateString) {
errors.date = "Enter a date"
}
return errors
}
return (
<div>
<div className="row" style={{marginBottom: "5px"}}>
<div className="col-sm-6 text-left no-padding">
Default Pay Rates
<i className="fa fa-question text-primary"
data-toggle="tooltip"
title="When adding this task to an employee, if there are default pay rates they will automatically be added to the employee for that task. They can be modified after the task is added."
aria-hidden="true"></i>
</div>
<PayRatesAddRemoveComponent
payRateIndicesToDelete={this.state.payRateIndicesToDelete}/>
</div>
<PayRatesListComponent
payRates={this.state.payRates}
selectedPayRateIndex={this.state.selectedPayRateIndex}
onChange={(e) => {
}}/>
<NewPayRateRow
value={this.state.currentPayRate}
validator={validator}
onPayRateAmountChange={(value) => {}}
onPayRateDateChange={(value) => {}} />
</div>
)
}
}
// validation logic
/**
* 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
}
单击任务会成功更新_currentTaskObject
及其Payrates
,但是React并不知道。
我去检查React开发者控制台时得到空数组。
除了在React中重写整个页面外,我该怎么做才能使React Component知道其所需数据状态的变化?