代码之家  ›  专栏  ›  技术社区  ›  tcoulson

setState未在componentWillReceiveProps内部更新

  •  2
  • tcoulson  · 技术社区  · 6 年前

    我觉得我打电话给setState的方式是正确的,但我想确保我没有打错地方。看看是否有人能发现错误。在控制台日志中,状态保持以前的值,而不是新的清除值。这是我的密码:

    componentWillReceiveProps(nextProps) {
        if (nextProps.value !== this.state.value && typeof nextProps.value !== 'undefined'){
            let changeVal = nextProps.value;
            let changeDisplay = nextProps.value;
            if(this.props.entryType === 'date') changeVal = Moment(nextProps.displayValue).format(this.props.format).toString();
            if(this.props.entryType === 'currency'||this.props.entryType === 'number'){
                if(isNaN(parseFloat(changeVal))){
                    changeVal = 0;
                    changeDisplay = 0;
                }
            }
            if(this.props.entryType === 'drop' || this.props.entryType === 'boolean'){
                if(this.props.options) {
                    this.props.options.map(x => {
                        if (x.value == changeVal || x.sortOrder == changeVal){
                            changeDisplay = x.label;
                            changeVal = x.value;
                        }
                    })
                }
            }
            this.setState({value: changeVal, displayValue: changeDisplay, selectValue:{value:changeVal, label:changeDisplay}}, ()=>{
                console.log("current displayValue",this.state, nextProps, this.props)
            });
        }
    }
    

    显然,我是在setState之后调用console,但该值不会更新。

    编辑:谢谢你的回复。我将尝试拆分props update state方法。我创建了一个拖放系统,可以将项目拖入或拖出组。很好,但它在该层次结构中有一个“容器”>“树”>“项”>“查询值”组件。这里的问题在于,容器需要知道整个树,才能将其构建出来,但是对内容的编辑是在QueryValue中进行的。所以我有一个方法,我可以通过这个链来通知容器任何更改。但我可能需要将容器数据与QueryValue数据分离。

    2 回复  |  直到 6 年前
        1
  •  3
  •   Pandaiolo    6 年前

    你的代码很复杂,所以我建议你试着重构它。

    但无论如何,我建议使用“componentDidUpdate”

    • 因为“componentWillReceiveProps”已被弃用,并可能导致副作用和复杂的状态流,这有利于代码中的错误

    React文档(用于“componentDidUpdate”):

    https://reactjs.org/docs/react-component.html#componentdidupdate


    反应文档(用于“不安全组件将接收道具”):

    https://reactjs.org/docs/react-component.html#unsafe_componentwillreceiveprops


    Note: 
    
    Using this lifecycle method often leads to bugs and inconsistencies, and for that reason it is going to be deprecated in the future.
    
    If you need to perform a side effect (for example, data fetching or an animation) in response to a change in props, use componentDidUpdate lifecycle instead.
    
    For other use cases, follow the recommendations in this blog post about derived state.
    
    If you used componentWillReceiveProps for re-computing some data only when a prop changes, use a memoization helper instead.
    
    If you used componentWillReceiveProps to “reset” some state when a prop changes, consider either making a component fully controlled or fully uncontrolled with a key instead.
    
    In very rare cases, you might want to use the getDerivedStateFromProps lifecycle as a last resort.
    
        2
  •  1
  •   Pandaiolo    6 年前

    正如@Tzook Bar Noy所解释的,React团队强烈建议不要使用 componentWillReceiveProps 生命周期方法。你可以用 componentDidUpdate 但它也被认为是一个坏习惯 setState 函数内部:它可能导致无限循环 componentWillUpdate -> setState -> componentWillUpdate -> setState -> etc 如果你不能正确地管理你的边界。

    我建议,因为您在代码中没有使用实例方法,所以使用新的 getDerivedStateFromProps 静态方法。此方法在组件装载和组件更新时使用当前道具和状态调用。它使用返回的对象选择性地更新组件状态。

    如果它适用于您的用例,请签入react docs。有趣的文章: https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html

    你的代码可能是这样的:

        getDerivedStateFromProps(props, state) {
            if (props.value !== state.value && typeof props.value !== 'undefined') {
                let changeVal = props.value
                let changeDisplay = props.value
                if (entryType === 'date')
                    changeVal = Moment(props.displayValue)
                        .format(format)
                        .toString()
                if (
                    entryType === 'currency' ||
                    entryType === 'number'
                ) {
                    if (isNaN(parseFloat(changeVal))) {
                        changeVal = 0
                        changeDisplay = 0
                    }
                }
                if (
                    entryType === 'drop' ||
                    entryType === 'boolean'
                ) {
                    if (options) {
                        options.map(x => {
                            if (x.value == changeVal || x.sortOrder == changeVal) {
                                changeDisplay = x.label
                                changeVal = x.value
                            }
                        })
                    }
                }
                return {
                    value: changeVal,
                    displayValue: changeDisplay,
                    selectValue: { value: changeVal, label: changeDisplay }
                }
            }
            return null
        }