ReactJS主要组件可从其范围之外访问动态数据

时间:2019-04-04 19:40:29

标签: javascript reactjs

我试图通过编写一个React组件来处理页面中容易出错的部分,从而使用ReactJS来修复完全在jQuery中实现的页面。该页面是一个“编辑任务”页面,其中包含多个部分,其中一个部分称为“薪资”部分

页面状态可以这样描述:

它包含TaskObject个集合,每个集合具有PayratesPermissions

我正在尝试传递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开发者控制台时得到空数组。 enter image description here

除了在React中重写整个页面外,我该怎么做才能使React Component知道其所需数据状态的变化?

0 个答案:

没有答案