2016-05-03 1 views
15

Sto provando a separare un componente di presentazione da un componente contenitore. Ho un SitesTable e un SitesTableContainer. Il contenitore è responsabile dell'attivazione di azioni di redux per recuperare i siti appropriati in base all'utente corrente. Il problema è che l'utente corrente viene prelevato in modo asincrono, dopo che il componente contenitore è stato reso inizialmente. Ciò significa che il componente contenitore non sa che è necessario rieseguire il codice nella sua funzione componentDidMount che aggiornerebbe i dati da inviare allo SitesTable. Penso che ho bisogno di rerender il componente contenitore quando uno dei suoi oggetti di scena (utente) cambia. Come faccio a farlo correttamente?il componente di risposta del rerender durante le modifiche del puntello

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

avete alcune altre funzioni disponibili, come componentDidUpdate, o probabilmente il vostro cercando, componentWillReceiveProps (nextProps) se si vuole sparare qualcosa quando gli oggetti di scena modifiche – thsorens

+0

Perché è necessario ri-renderizzare SitesTable se non sta cambiando i suoi oggetti di scena? – QoP

+0

@QoP le azioni inviate in 'componentDidMount' cambieranno il nodo' sites' nello stato dell'applicazione, che viene passato in 'SitesTable'. Il nodo 'sites' di SitesStable cambierà. – David

risposta

25

È necessario aggiungere una condizione nel metodo componentWillReceiveProps.

Questo è il modo in cui il componente dovrebbe essere simile

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

Si noti che JSON.stringify può essere utilizzato solo per questo tipo di confronto, se è stabile (in base alle specifiche non lo è), quindi produce lo stesso output per gli stessi input. Si consiglia di confrontare le proprietà id degli oggetti utente o di passare userId-s negli oggetti di scena e di confrontarli per evitare ricariche non necessarie. –

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

Credo che questo sia l'evento che vi serve. I trigger componentWillReceiveProps si attivano ogni volta che il componente riceve qualcosa tramite i puntelli. Da lì puoi avere il tuo controllo e poi fare qualsiasi cosa tu voglia fare.

2

Suggerirei di dare un'occhiata a questo mio answer e vedere se è rilevante per ciò che si sta facendo. Se capisco il tuo vero problema, è che semplicemente non stai usando la tua azione asincrona correttamente e aggiorni il "negozio" di redux, che aggiornerà automaticamente il tuo componente con i suoi nuovi oggetti di scena.

Questa sezione del codice:

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

Non dovrebbe essere innescando in un componente, pertanto deve essere trattato dopo l'esecuzione tua prima richiesta.

Date un'occhiata a questo esempio da 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)) 
    ); 
    }; 
} 

Non devono necessariamente utilizzare redux-thunk, ma vi aiuterà a ragionare su scenari come questo e scrivere il codice da abbinare.

+0

giusto, ho capito. Ma dove spedite esattamente "makeASandwichWithSecretSauce" nel vostro componente? – David

+0

Ti collegherò a un repository con un esempio pertinente, utilizzi react-router con la tua app? – TameBadger

+0

sì, io uso react-router – David

Problemi correlati