2015-04-01 57 views
24

我遇到過有關基於屬性的狀態的問題。改變狀態,當屬性改變時,首先掛載在React - Missing函數上?

場景

我有一個組件父項,它將創建一個屬性傳遞給子組件。 子組件根據收到的屬性做出反應。 在React中,改變組件狀態的「唯一」正確方法是使用函數componentWillMount或componentDidMount和componentWillReceiveProps,據我所見(除此之外,但讓我們關注這些組件,因爲getInitialState只執行一次) 。

我的問題/問題

如果我收到來自父一個新的屬性,我想改變狀態,只有功能componentWillReceiveProps將被執行,將允許我執行的setState。渲染不允許setStatus。

如果我想設置開始時的狀態以及接收新屬性的時間,該怎麼辦? 所以我必須將它設置在getInitialState或componentWillMount/componentDidMount上。然後,您必須根據使用componentWillReceiveProps的屬性更改狀態。

這是一個問題,當你的狀態高度依賴於你的屬性,這幾乎總是。這可能會變得愚蠢,因爲你必須根據新的屬性重複你想要更新的狀態。

我的解決方案

我創建了一個,這就是所謂的componentWillMount和componentWillReceiveProps新方法。在渲染之前更新屬性並且第一次安裝組件後,我還沒有找到任何方法被調用。那麼就不需要做這個愚蠢的解決方法。

無論如何,這裏的問題:沒有更好的選擇來更新狀態時,收到新的屬性或更改?

/*...*/ 
/** 
* To be called before mounted and before updating props 
* @param props 
*/ 
prepareComponentState: function (props) { 
    var usedProps = props || this.props; 

    //set data on state/template 
    var currentResponses = this.state.candidatesResponses.filter(function (elem) { 
     return elem.questionId === usedProps.currentQuestion.id; 
    }); 
    this.setState({ 
     currentResponses: currentResponses, 
     activeAnswer: null 
    }); 
}, 
componentWillMount: function() { 
    this.prepareComponentState(); 
}, 
componentWillReceiveProps: function (nextProps) { 
    this.prepareComponentState(nextProps); 
}, 
/*...*/ 

我覺得有點傻,我想我失去的東西...... 我想有另一種解決方案來解決這個問題。

,是的,我已經知道這一點: https://facebook.github.io/react/tips/props-in-getInitialState-as-anti-pattern.html

回答

20

我發現,這種模式通常不是非常必要的。 在一般情況下,(並非總是),我發現基於更改屬性的設置狀態有點反模式;相反,只需在呈現時導出必需的本地狀態。

render: function() { 
    var currentResponses = this.state.candidatesResponses.filter(function (elem) { 
    return elem.questionId === this.props.currentQuestion.id; 
    }); 

    return ...; // use currentResponses instead of this.state.currentResponses 
} 

然而,在某些情況下,它可以是有意義的緩存此數據(例如,計算可能是昂貴),或者你只需​​要當道具設置/改變了一些其他的原因就知道了。在這種情況下,我會基本上使用您在問題中編寫的模式。

如果你真的不喜歡打字出來,你可以將這種新方法形式化爲混合。例如:

var PropsSetOrChangeMixin = { 
    componentWillMount: function() { 
    this.onPropsSetOrChange(this.props); 
    }, 

    componentWillReceiveProps: function(nextProps) { 
    this.onPropsSetOrChange(nextProps); 
    } 
}; 

React.createClass({ 
    mixins: [PropsSetOrChangeMixin], 

    onPropsSetOrChange: function(props) { 
    var currentResponses = this.state.candidatesResponses.filter(function (elem) { 
     return elem.questionId === props.currentQuestion.id; 
    }); 

    this.setState({ 
     currentResponses: currentResponses, 
     activeAnswer: null 
    }); 
    }, 

    // ... 
}); 

當然,如果你使用基於class反應的組分,你需要找一些替代的解決方案(如繼承,或自定義JS混入),因爲他們沒有得到React-現在混合風格。

(對於它的價值,我覺得代碼是用明確的方式更清晰;我可能會寫這樣的:)

componentWillMount: function() { 
    this.prepareComponentState(this.props); 
}, 

componentWillReceiveProps: function (nextProps) { 
    this.prepareComponentState(nextProps); 
}, 

prepareComponentState: function (props) { 
    //set data on state/template 
    var currentResponses = this.state.candidatesResponses.filter(function (elem) { 
    return elem.questionId === props.currentQuestion.id; 
    }); 
    this.setState({ 
    currentResponses: currentResponses, 
    activeAnswer: null 
    }); 
},