ref – original github
source, with my comments and logs
The app starts off with ReactDOM.render
1 2 3 4 5 6 |
const createStoreWithMiddleware = applyMiddleware()(createStore); ReactDOM.render( ... createStoreWithMiddleware(reducers) ... ) |
where we use redux’s applyMiddleware and createStore to create a store with some combinedReducers:
1 2 3 4 |
const reducers = combineReducers({ contacts: ContactsReducer, activeContact: ActiveContactReducer }); |
Pay attention here in that a property is mapped to a reducer. So whatever data the reducer returns will be mapped to that property. And that property is kept in the store.
Our reducers are initialized with starting state
for example, ContactsReducer is imported from:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
export default function () { console.log('reducers/reducer_contacts.js - index') return [{ "name": "Miguel", "phone": "123456789", },{ "name": "Peter", "phone": "883292300348", },{ "name": "Jessica", "phone": "8743847638473", },{ "name": "Michael", "phone": "0988765553", }]; } |
So this means store’s contacts property now has an array of member names and phones.
These reducers are then run with initial state and type at @@redux/INIT
Then the store is created.
Each component’s mapStateToProps will run first, because we need to map the state from our store onto our component’s props.
The component does this and receives the store’s state.
1 |
{contacts: Array(4), activeContact: null} |
It takes what it needs and creates contacts property and initializes with our store’s state’s contacts data.
1 |
contacts: state.contacts |
Then component then renders. After finishing rendering, the componentDidMount is called.
Finally, the app’s componentDidMount will be called.
Provider’s prop store let’s children components access . data
Notice that App is within Provider.
1 2 3 |
<Provider store={createStore(reducers)}> <App /> </Provider> |
or
1 2 3 4 5 6 |
<Provider store={store}> <View style={{ width: '100%', height: '100%' }}> <App /> <Alert /> </View> </Provider> |
The
Since any React component in a React Redux app can be connected, most applications will render a
Normally, you can’t use a connected component unless it is nested inside of a < Provider >.
Hence, our App will be connected.
components/app.js
App is the main container. It houses two other components. Thus, the store data will be available to all containers.
Namely, these containers are ContactList and ContactDetail.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
import React, { Component } from 'react'; import ContactList from '../containers/contact-list' import ContactDetail from '../containers/contact-detail' export default class App extends Component { render() { return ( <div> <ContactList /> <ContactDetail /> </div> ); } } |
Mapping Redux store state to Component props
1 2 3 4 5 6 7 |
const rootReducer = combineReducers({ contacts: ContactsReducer, activeContact: ActiveContactReducer, myID: IdReducer }); export default rootReducer; |
and
1 |
createStoreWithMiddleware(reducers) |
The contacts, and activeContact property is now available in our state object.
Now, look at a component’s mapStateToProps. Basically, it gets the store’s state as the parameter, and then extract whatever property we need and return it to the component. i.e contacts
Thus, after mapStateToProps is run, you’ll be able to do use it like so:
1 |
this.props.contacts |
such as in renderList().
The important thing here is that once we declared our mapStateToProps function, we map it to the connect function.
Thus, whenever the data changes, it will call our mapStateToProps.
1 2 3 4 5 6 7 8 9 |
// connects a part of the “redux state” to the props of a React component function mapStateToProps(state) { return { contacts: state.contacts }; } // we then connect these functions to this component export default connect(mapStateToProps, mapDispatchToProps)(ContactList) |
Mapping Action to Component props
In our case, when we return an action object with type and payload properties, they are called Action Creators.
Action creators are exactly that—functions that create actions.
In contact list component, there is an onClick handler like so:
1 2 3 4 5 6 7 8 9 10 |
renderList() { return this.props.contacts.map((contact) => { return ( <li ... onClick={() => this.props.selectContact(contact)} ... ); }); } |
The selectContact is imported from actions/action-select-contact.js
1 2 3 4 5 6 7 8 9 |
function selectContact(contact) { return { type: 'CONTACT_SELECTED', payload: { name: "reeecky", phone: "123" } } } |
when the handler is clicked, the action function selectContact is called. It returns an object.
Take note that this reducer is mapped to property activeContact in combineReducers
{name: ‘Michael’, phone: ‘0988765553’}
with type CONTACT_SELECTED
This is the action object.
Then, ALL reducer functions are then called to see if this action type CONTACT_SELECTED is theirs.
It happens so that our reducer_active_contacts.js reducer function takes care of this CONTACT_SELECTED.
We see the action being passed in
{type: ‘CONTACT_SELECTED’, payload: {…}}
The reducer returns the payload object. The component will then map this payload to its prop property say ‘contact’ by using mapStateToProps
1 2 3 4 5 |
function mapStateToProps(state) { return { contact: state.activeContact }; } |
Now the active contact components will render with the new data.