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.
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); –
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 –
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. –