2016-05-03 20 views
15

Tôi đang cố tách riêng một thành phần trình bày khỏi thành phần vùng chứa. Tôi có một số SitesTableSitesTableContainer. Vùng chứa chịu trách nhiệm kích hoạt các tác vụ redux để tìm nạp các trang web phù hợp dựa trên người dùng hiện tại. Vấn đề là người dùng hiện tại được tìm nạp không đồng bộ, sau khi thành phần vùng chứa được hiển thị ban đầu. Điều này có nghĩa là thành phần vùng chứa không biết rằng nó cần phải thực thi lại mã trong hàm componentDidMount của nó, sẽ cập nhật dữ liệu để gửi đến SitesTable. Tôi nghĩ rằng tôi cần phải trở lại thành phần container khi một trong những thay đổi đạo cụ (người dùng) của nó. Làm thế nào để tôi làm điều này một cách chính xác?thành phần phản ứng lại khi prop thay đổi

class SitesTableContainer extends React.Component { 
    static get propTypes() { 
     return { 
     sites: React.PropTypes.object, 
     user: React.PropTypes.object, 
     isManager: React.PropTypes.boolean 
     } 
    } 

    componentDidMount() { 
     if (this.props.isManager) { 
     this.props.dispatch(actions.fetchAllSites()) 
     } else { 
     const currentUserId = this.props.user.get('id') 
     this.props.dispatch(actions.fetchUsersSites(currentUserId)) 
     } 
    } 

    render() { 
     return <SitesTable sites={this.props.sites}/> 
    } 
} 

function mapStateToProps(state) { 
    const user = userUtils.getCurrentUser(state) 

    return { 
    sites: state.get('sites'), 
    user, 
    isManager: userUtils.isManager(user) 
    } 
} 

export default connect(mapStateToProps)(SitesTableContainer); 
+0

bạn có một số chức năng khác có sẵn, như componentDidUpdate, hoặc có lẽ là một bạn đang tìm kiếm, componentWillReceiveProps (nextProps) nếu bạn muốn bắn một cái gì đó khi các đạo cụ thay đổi – thsorens

+0

Tại sao bạn cần phải kết xuất lại SitesTable nếu nó không thay đổi đạo cụ của nó? – QoP

+0

@QoP các hành động được gửi đi trong 'componentDidMount' sẽ thay đổi nút' sites' trong trạng thái ứng dụng, được chuyển vào 'SitesTable'. Nút 'sites' của SitesStable sẽ thay đổi. – David

Trả lời

25

Bạn phải thêm điều kiện trong phương thức componentWillReceiveProps của mình.

Đây là cách thành phần của bạn sẽ trông như thế

constructor(){ 
    this.updateUser = this.updateUser.bind(this); 
} 


componentDidMount() { 
    this.updateUser(); 

} 

componentWillReceiveProps(nextProps) { 
    if(JSON.stringify(this.props.user) !== JSON.stringify(nextProps.user)) // Check if it's a new user, you can also use some unique, like the ID 
    { 
      this.updateUser(); 
    } 
} 

updateUser() { 
    if (this.props.isManager) { 
    this.props.dispatch(actions.fetchAllSites()) 
    } else { 
    const currentUserId = this.props.user.get('id') 
    this.props.dispatch(actions.fetchUsersSites(currentUserId)) 
    } 
} 
+0

Lưu ý rằng JSON.stringify chỉ có thể được sử dụng cho loại so sánh này, nếu nó ổn định (theo đặc tả nó không phải là), vì vậy nó tạo ra cùng một đầu ra cho cùng một đầu vào. Tôi khuyên bạn nên so sánh các thuộc tính id của đối tượng người dùng hoặc chuyển userId-s trong đạo cụ và so sánh chúng để tránh tải lại không cần thiết. –

5
componentWillReceiveProps(nextProps) { // your code here} 

Tôi nghĩ đó là sự kiện mà bạn cần. componentWillReceiveProps kích hoạt bất cứ khi nào thành phần của bạn nhận được một cái gì đó thông qua đạo cụ. Từ đó bạn có thể có kiểm tra của bạn sau đó làm bất cứ điều gì bạn muốn làm.

2

Tôi khuyên bạn nên xem số answer của tôi và xem liệu nó có liên quan đến những gì bạn đang làm hay không. Nếu tôi hiểu vấn đề thực sự của bạn, đó là việc bạn không sử dụng hành động async của mình một cách chính xác và cập nhật redux "store", nó sẽ tự động cập nhật thành phần của bạn với các đạo cụ mới.

Phần này của mã của bạn:

componentDidMount() { 
     if (this.props.isManager) { 
     this.props.dispatch(actions.fetchAllSites()) 
     } else { 
     const currentUserId = this.props.user.get('id') 
     this.props.dispatch(actions.fetchUsersSites(currentUserId)) 
     } 
    } 

nên không được kích hoạt trong một thành phần, nó cần được xử lý sau khi thực hiện yêu cầu đầu tiên của bạn.

Hãy nhìn vào ví dụ này từ redux-thunk:

function makeASandwichWithSecretSauce(forPerson) { 

    // Invert control! 
    // Return a function that accepts `dispatch` so we can dispatch later. 
    // Thunk middleware knows how to turn thunk async actions into actions. 

    return function (dispatch) { 
    return fetchSecretSauce().then(
     sauce => dispatch(makeASandwich(forPerson, sauce)), 
     error => dispatch(apologize('The Sandwich Shop', forPerson, error)) 
    ); 
    }; 
} 

Bạn không nhất thiết phải sử dụng Redux-thunk, nhưng nó sẽ giúp bạn suy luận về các tình huống như thế này và viết mã để phù hợp.

+0

đúng, tôi hiểu điều đó. Nhưng chính xác thì bạn gửi 'makeASandwichWithSecretSauce' trong thành phần của bạn ở đâu? – David

+0

Tôi sẽ liên kết bạn với một repo với một ví dụ có liên quan, bạn có sử dụng bộ phản ứng-router với ứng dụng của mình không? – TameBadger

+0

có tôi sử dụng phản ứng-router – David

Các vấn đề liên quan