setState不在componentWillReceiveProps内部更新

时间:2018-08-01 13:04:05

标签: reactjs

我觉得我正在以适当的方式致电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之后调用控制台,但是该值不会更新。

编辑:感谢您的答复。我将尝试撕裂道具更新状态方法。我创建了一个拖放系统,可以在其中拖放项目。效果很好,但是在该层次结构中具有“容器”>“树”>“项目”>“ QueryValue”组件。这里的问题在于,容器需要了解整个树,才能将其构建出来,但是对内容的编辑在QueryValue中进行。因此,我有一种方法可以遍历整个链,该方法可以让我将任何更改通知Container。但是我可能需要将Container数据与QueryValue数据分离。

2 个答案:

答案 0 :(得分:3)

您的代码非常复杂,因此我建议尝试对其进行重构。

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

  • 因为“ componentWillReceiveProps”已被弃用,并且可能导致副作用和复杂的状态流,从而增加了代码中的错误

反应文档(针对“ componentDidUpdate”):

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


反应文档(用于“ UNSAFE_componentWillReceiveProps”):

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.

答案 1 :(得分:1)

正如@Tzook Bar Noy所解释的,React团队强烈建议不要使用componentWillReceiveProps生命周期方法。您可以使用componentDidUpdate,但在该函数中使用setState也被认为是不好的做法:如果您无法正确管理边界,则可能导致无限循环componentWillUpdate -> setState -> componentWillUpdate -> setState -> etc

由于您在代码中未使用实例方法,因此我建议您使用新的getDerivedStateFromProps静态方法。当组件安装和组件更新时,将使用当前的props和state调用此方法。它使用返回的对象来有选择地更新组件状态。

检入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
    }