2016-02-09 23 views
30

Forse non sto spostando la testa su redux, ma tutti gli esempi che ho visto in realtà non accedono troppo allo stato tra i contenitori e quindi non ho visto molto l'uso di store.getState(), ma anche se tu vuoi spedire, hai bisogno di accedere al negozio, giusto?Redux, Devo importare il negozio in tutti i miei contenitori se voglio avere accesso ai dati?

Quindi, altro che importare negozio importazione da 'path/to/negozio/store'

in ogni file che voglio getState() o "spedizione", come faccio a ottenere l'accesso a quello stato perché se non lo includo, il negozio non è definito.

risposta

51

In generale si vuole fare solo i componenti contenitore di livello superiore quelli che hanno accesso al negozio - passeranno verso il basso tutti i dati necessari o dispacci d'azione come puntelli per i loro componenti figli. Questa è la differenza tra un componente "intelligente" e uno "stupido" - i componenti "intelligenti" conoscono lo store/stato di Redux, mentre i componenti "stupidi" ricevono solo oggetti di scena passati a loro e non hanno idea dello stato dell'applicazione più grande.

Tuttavia, anche solo il passaggio del negozio ai componenti del contenitore può diventare noioso. Ecco perché React-Redux fornisce un componente pronto all'uso che avvolge l'intera applicazione. Check it out nei documenti. Questo è il componente Provider e quando si avvolgono tutta la tua app con esso, si passa solo il negozio per un componente volta:

import createStore from '../store'; 

const store = createStore() 

class App extends Component { 

    render() { 
    return (
     <Provider store={store}> 
     <MainAppContainer /> 
     </Provider> 
    ) 
    } 
} 

Come si può vedere qui, ho un file di configurazione separato solo per il mio negozio Dato che c'è un sacco di modifiche che puoi fare e per qualsiasi app da remoto, ti troverai a fare lo stesso per cose come l'uso di compose per applicare il middleware.

Quindi uno dei componenti rimanenti "intelligenti" (generalmente wrapper) deve ascoltare il negozio. Questo è realizzato usando il metodo connect. Ciò consente di associare parti dello stato alle proprietà del componente e azioni di invio come proprietà.

import { bindActionCreators } from 'redux'; 
import { connect } from 'react-redux'; 
import * as actionCreators from './actionCreators'; 

const mapStateToProps = function(state){ 
    return { 
    something: state.something, 
    } 
} 

const mapDispatchToProps = function (dispatch) { 
    return bindActionCreators({ 
    getSomething: actionCreators.getSomething, 
    }, dispatch) 
} 

class MainAppContainer extends Component { 

    componentDidMount() { 
     //now has access to data like this.props.something, which is from store 
     //now has access to dispatch actions like this.props.getSomething 
    } 

    render() { 
     //will pass down store data and dispatch actions to child components 
     return (
       <div> 
        <ChildComponent1 something={this.props.something} /> 
        <ChildComponent2 getSomething={this.props.getSomething} /> 
       </div> 
     ) 
    } 
} 

export default connect(mapStateToProps, mapDispatchToProps)(MainAppContainer) 

Poiché si sta sempre di passaggio verso il basso le azioni di spedizione e di dati al componente figli come proprietà, è solo di riferimento quelli su tale componente con this.props.

Partendo Nell'esempio qui sopra, vedrete che ho passato a causa this.props.something a ChildComponent1, ha accesso ai dati something dal negozio, ma non ha accesso all'azione getSomething spedizione. Allo stesso modo, ChildComponent2 ha accesso solo all'azione di invio getSomething ma non ai dati something. Ciò significa che esponi solo i componenti esattamente a ciò di cui hanno bisogno dal negozio.

Ad esempio, poiché ChildComponent2 stato tramandato l'azione spedizione come getSomething, nel mio onClick posso chiamare this.props.getSomething e chiamerà l'azione spedizione senza bisogno di alcun accesso al negozio. Allo stesso modo può continuare a passare getSomething a un altro componente figlio e quel componente potrebbe chiamarlo e/o passarlo e il ciclo potrebbe continuare indefinitamente.

class ChildComponent2 extends Component { 

    render() { 
     return (
      <div> 
       <div onClick={this.props.getSomething}>Click me</div> 
       <NestedComponent getSomething={this.props.getSomething} /> 
      </div> 
     ) 
    } 
} 

Edit dai commenti

Anche se questo non riguarda direttamente alla domanda, nei commenti che sembrava un po 'confuso su azioni. Non ho effettivamente definito l'azione getSomething qui. Invece, nelle app Redux è normale mettere tutte le definizioni delle azioni in un file separato chiamato actionCreators.js. Questo contiene funzioni che hanno lo stesso nome delle tue azioni e restituiscono un oggetto con una proprietà type e qualsiasi altro metodo/dato richiesto dall'azione. Per esempio, ecco un semplice file di esempio actionCreators.js:

export function getSomething() { 
    return { 
     type: 'GET_SOMETHING', 
     payload: { 
      something: 'Here is some data' 
     } 
    } 
} 

Questo tipo di azione è quello che il vostro riduttore avrebbe ascoltato per sapere quale azione è stata di essere licenziato.

+0

grazie !! Ora, cosa succede se hai un componente figlio uner MainAppContainer, diciamo, "childAppContainer", puoi mostrare un esempio di come poi gestirò lo stato e disperdendo un'azione? Quindi, se si desidera "aggiornare" lo stato in ChildComponent2, si potrebbe dire qualcosa come "getSomething.AddSomething.dispatch (SOME_CONST_ACTION_NAME); –

+0

fratello, mi ucciderai! Lol .. Hai aiutato moltissimo, grazie! Ma sono un po '(e ho letto i documenti), storto nel capire come funziona la funzione "this.props.getSomething", ottiene un actionType - non lo passeresti? Suppongo che tu non stia usando il beato di invio Grazie ancora, e se questo è troppo lol, capisco perfettamente, non preoccuparti –

+2

Non preoccuparti, amico: non ho impostato un tipo di azione su 'getSomething' o lo definisco perché di solito le persone definiscono tutte le azioni per la loro app in un file separato chiamato 'actionCreators.js'. Questo sarebbe un file pieno di funzioni che restituiscono un oggetto con una proprietà' type' e qualsiasi altra cosa necessaria per l'azione. Quindi su quel componente dovrei effettivamente importare il divertimento 'getSomething' da 'actionCreators.js' come pure dal modulo' bindActionCreators' da 'redux'. Ho omesso quelle istruzioni di importazione per ripulire un po 'il codice, ma posso aggiungerle di nuovo. –

8

Se si utilizza il pacchetto react-redux, si termina il wrapping dei componenti in un Provider con un puntello store. In questo modo si imposta il singolo negozio in un contesto React, a cui si accede dal metodo connect nei componenti figlio. Il metodo connect accetta due funzioni (mapStateToProps e mapDispatchToProps), che sono i tuoi ganci per ottenere lo stato dal negozio e inviare messaggi.

Take a look here for more information

+4

Quindi, se si dispone di 10 componenti del contenitore, ciascun componente del contenitore dovrà disporre della propria implementazione connect(), mapStateToProps() e mapDispatchToProps()? Come si risparmia digitazione e tempo? Ho pensato che ogni componente del contenitore potesse accedere direttamente al negozio. Il caso di utilizzo prototipo sarebbe un oggetto Utente che deve essere accessibile ovunque a quasi tutti i componenti figlio e nipote. In che modo i bambini possono accedere facilmente all'oggetto Utente all'interno del negozio? – user798719

+0

@ user798719 è ancora possibile accedere allo store e non utilizzare mapStateToProps() e mapDispatchToProps(), ma si accoppieranno strettamente i componenti per ridurli. –

Problemi correlati