2015-04-01 19 views
24

Tôi đã gặp một vấn đề về các tiểu bang dựa trên các thuộc tính.Thay đổi trạng thái khi thuộc tính thay đổi và gắn kết đầu tiên trên React - Thiếu chức năng?

Kịch bản

Tôi có phụ huynh thành phần tạo thuộc tính chuyển cho thành phần con. Thành phần con phản ứng theo tài sản nhận được. Phản ứng cách duy nhất để thay đổi trạng thái của một thành phần là sử dụng hàm componentWillMount hoặc componentDidMount và componentWillReceiveProps như tôi đã thấy (trong số những người khác, nhưng hãy tập trung vào những thành phần này, vì getInitialState chỉ được thực hiện một lần) .

Vấn đề của tôi/Câu hỏi

Nếu tôi nhận được một tài sản mới từ cha mẹ và tôi muốn thay đổi trạng thái, chỉ có componentWillReceiveProps chức năng sẽ được thực hiện và sẽ cho phép tôi thực hiện setstate. Render không cho phép setStatus.

Nếu tôi muốn đặt trạng thái lúc đầu và thời gian nhận trạng thái mới thì sao? Vì vậy, tôi phải đặt nó trên getInitialState hoặc componentWillMount/componentDidMount. Sau đó, bạn phải thay đổi trạng thái tùy thuộc vào các thuộc tính sử dụng componentWillReceiveProps.

Đây là vấn đề khi tiểu bang của bạn phụ thuộc nhiều vào tài sản của bạn, hầu như luôn luôn như vậy. Điều này có thể trở nên ngớ ngẩn vì bạn phải lặp lại các trạng thái mà bạn muốn cập nhật theo thuộc tính mới.

Giải pháp của tôi

Tôi đã tạo ra một phương pháp mới mà nó được gọi là trên componentWillMount và trên componentWillReceiveProps. Tôi đã không tìm thấy bất kỳ phương pháp được gọi là sau khi một tài sản đã được cập nhật trước khi render và cũng là lần đầu tiên các thành phần được gắn kết. Sau đó, sẽ không có cần phải làm việc này ngớ ngẩn.

Dù sao, ở đây câu hỏi: không có tùy chọn nào tốt hơn để cập nhật trạng thái khi một thuộc tính mới được nhận hoặc thay đổi không?

/*...*/ 
/** 
* 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); 
}, 
/*...*/ 

tôi cảm thấy một chút ngu ngốc, tôi đoán tôi mất một cái gì đó ... Tôi đoán có một giải pháp để giải quyết việc này.

Và yeah, tôi đã biết về điều này: https://facebook.github.io/react/tips/props-in-getInitialState-as-anti-pattern.html

Trả lời

20

Tôi đã phát hiện ra rằng mô hình này thường không phải là rất cần thiết. Trong trường hợp chung (không phải lúc nào), tôi đã thấy rằng trạng thái cài đặt dựa trên các thuộc tính đã thay đổi là một chút chống mẫu; thay vào đó, chỉ cần lấy được trạng thái địa phương cần thiết tại thời gian hiển thị.

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 
} 

Tuy nhiên, trong một số trường hợp, nó có thể làm cho tinh thần để bộ nhớ cache dữ liệu này (ví dụ có thể tính toán nó là tốn kém), hoặc bạn chỉ cần phải biết khi nào đạo cụ được thiết lập/thay đổi đối với một số lý do khác. Trong trường hợp đó, tôi sẽ sử dụng về cơ bản mẫu bạn đã viết trong câu hỏi của bạn.

Nếu bạn thực sự không thích nhập, bạn có thể chính thức hóa phương thức mới này làm bản mixin.Ví dụ:

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 
    }); 
    }, 

    // ... 
}); 

Tất nhiên, nếu bạn đang sử dụng class -dựa Phản ứng linh kiện, bạn cần phải tìm thấy một số giải pháp thay thế (ví dụ như thừa kế, hoặc mixins JS tùy chỉnh) vì họ không có được React- phong cách mixins ngay bây giờ.

(Đối với những gì nó có giá trị, tôi nghĩ rằng mã là rõ ràng hơn nhiều bằng cách sử dụng phương pháp rõ ràng, tôi có lẽ muốn viết nó như thế này :)

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 
    }); 
}, 
Các vấn đề liên quan