Project Summary
This is a working project that currently only utilizes state and props to pass its data. Before getting started, try to get familiar with the code and see how props is being passed through to different components. In particular, take a look at src/App.js
. You’ll notice that src/App.js
is currently very large. With the use of redux
, will be able to turn src/App.js
into a small, 27 line, file.
During this project, I’ll be improving on a web application that walks users through filling out a home loan application. I’ll be modifying components that have already been built to use redux
. This allows us to keep track of data and pass it to the correct components via routing. I’ll be making changes to all files in the src/components
folder, except for src/components/Finish/Finish.js
, to modify them to work with redux
. I’ll also make changes to src/router.js
, src/index.js
and src/App.js
.
Live Example
Setup
fork
andclone
this repository.cd
into the project directory.- Run
npm i
to install current dependencies. - Run
npm i react-redux redux react-router-dom
- Run
npm start
( The app should intentionally not compile correctly ).
Step 1
Summary
In this step, we will create our store
.
When using redux, the store holds the entire state of our application. So it’s important we set this up first.
Instructions
- Create a new file in your
src
folder calledstore.js
- Open
src/store.js
. - Import
createStore
fromredux
. - Import
reducer.js
fromsrc/ducks/reducer.js
. - Export
createStore
by default and pass it reducer as it’s argument
Detailed Instructions
In redux, components need to connect to a store. Let’s create this store. Create a file in the src
folder called store.js
. I’ll only be needing one thing from redux
: createStore
. createStore
will allows us to export the creation of our store.
import { createStore } from "redux";
In order to create our store, I’ll also need our reducer. So let’s import that as well. Our reducer is located in src/ducks
.
import { createStore } from "redux";
import reducer from "./ducks/reducer";
Now that we have everything we need to import, let’s export by default the creation of our store.
import { createStore } from "redux";
import reducer from "./ducks/reducer";
export default createStore( reducer );
Solution
src/store.js
import { createStore } from "redux";
import reducer from "./ducks/reducer";
export default createStore( reducer );
Step 2
Summary
In this step, we will take our store created from the previous step and hook it up in src/index.js
. We will also make use of HashRouter
in App.js
to allow routing in the application. After this step, our app should compile correctly.
Instructions
- Open
src/index.js
. - Import
store
fromsrc/store.js
. - Import
Provider
fromreact-redux
.- The
Provider
component should have astore
prop that equalsstore
(remember how we reference variables in jsx).
- The
- Open
src/App.js
. - Import
HashRouter
fromreact-router-dom
. - Wrap the
router
invocation in<HashRouter>
tags.
Detailed Instructions
Since our store has been created, we can hook it up to our App in src/index.js
. This will allow our App to have access to the store and the reducers and will also allow our App to compile correctly. I’ll need to import Provider
from react-redux
and store
from src/store.js
.
import store from './store'
import { Provider } from 'react-redux'
The Provider
component will “provide” the store to our App. All we need to do is wrap the App
component with the Provider
component and give the Proivder
component a store
prop that equals store
.
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import './index.css';
import { Provider } from 'react-redux'
import store from './store'
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>
, document.getElementById('root'));
registerServiceWorker();
Open src/index.js
. Since we’re using routing I’ll be needing to import HashRouter
from react-router-dom
and wrap the router
invocation.
import { HashRouter } from 'react-router-dom'
render() {
return (
<div>
<HashRouter>
{
router( this.state.loanType, this.state.propertyType, this.handleChangeLoanType, this.handleChangePropertyType, this.handleChangePropertyToBeUsedOn, this.state.propToBeUsedOn, this.state.city, this.handleChangeCity, this.handleChangeFoundFalse, this.handleChangeFoundTrue, this.state.found, this.handleChangeRealEstateAgentTrue, this.handleChangeRealEstateAgentFalse, this.state.realEstateAgent, this.handleChangeUpdateDownPayment, this.state.downPayment, this.handleChangeUpdateCost, this.state.cost, this.state.credit, this.handleChangeCreditE, this.handleChangeCreditG,this.handleChangeCreditF, this.handleChangeCreditP, this.state.history, this.handleChangeUpdateHistory, this.state.addressOne, this.state.addressTwo, this.state.addressThree, this.handleChangeAddressOne, this.handleChangeAddressTwo, this.handleChangeAddressThree, this.handleChangeFirstName, this.handleChangeLastName, this.handleChangeEmail, this.state.firstName, this.state.lastName, this.state.email )
}
</HashRouter>
</div>
);
}
Solution
src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import './index.css';
import { Provider } from 'react-redux';
import store from './store';
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>
, document.getElementById('root'));
registerServiceWorker();
src/App.js
import { HashRouter } from 'react-router-dom';
render() {
return (
<div>
<HashRouter>
{
router( this.state.loanType, this.state.propertyType, this.handleChangeLoanType, this.handleChangePropertyType, this.handleChangePropertyToBeUsedOn, this.state.propToBeUsedOn, this.state.city, this.handleChangeCity, this.handleChangeFoundFalse, this.handleChangeFoundTrue, this.state.found, this.handleChangeRealEstateAgentTrue, this.handleChangeRealEstateAgentFalse, this.state.realEstateAgent, this.handleChangeUpdateDownPayment, this.state.downPayment, this.handleChangeUpdateCost, this.state.cost, this.state.credit, this.handleChangeCreditE, this.handleChangeCreditG,this.handleChangeCreditF, this.handleChangeCreditP, this.state.history, this.handleChangeUpdateHistory, this.state.addressOne, this.state.addressTwo, this.state.addressThree, this.handleChangeAddressOne, this.handleChangeAddressTwo, this.handleChangeAddressThree, this.handleChangeFirstName, this.handleChangeLastName, this.handleChangeEmail, this.state.firstName, this.state.lastName, this.state.email )
}
</HashRouter>
</div>
);
}
Step 3
Summary
Because we needed to pass state down to our routes, we had to make our routing a function. Currently, we’re exporting a function by default in our router.js
, by making this a function, we were able to import it into our App.js
and then pass it props through its arguments.
In addition to our route component being a function, the way we’re connecting our Route
to the correct component is using a render={()=> <Component prop={prop}/> path='/'}
instead of a component={Component} path='/'
. The reason we needed to use render this way was so we could pass props down through the Components element. However, this results in messy looking code.
In this step, we are going to clean up the mess.
Instructions
- Open
src/router.js
. - Instead of exporting a function, let’s remove the function and simply export the chunk of JSX that was returned by the function.
- You will start getting errors coming from the props on the routes rendered elements once our routing is no longer a function, this is because they’re no longer receiving information via parameters from the function and are now undefined.
- For each individual route, instead of using render, we will be using component.
- A route should look like the following:
<Route component={ theComponent } path='/thePath'/>
- A route should look like the following:
Now that we’ve changed our router.js
, no data is going to be passed to our other components, you will also get an error that says TypeError: __webpack_require__.i(...) is not a function
. This is because in our App.js
router is still being treated as a function.
- Open
src/App.js
. - Remove the invoking parenthesis from your
{router}
as well as the content inside of them.
Detailed Instructions
Let’s begin by opening src/router.js
. Since this will no longer be a function, all we need to do is export the content inside of the return statement and delete everything else that’s part of the function. I’ll also need to make modifications to each route so that it looks like: <Route component={ theComponent } path="/thePath" />
. When finished you’ll end up with:
export default (
<Switch>
<Route component={NextBtn} exact path= '/'/>
<Route component={WizardOne} path='/wOne'/>
<Route component={WizardTwo} path="/wTwo"/>
<Route component={WizardThree} path="/wThree"/>
<Route component={WizardFour} path="/wFour"/>
<Route component={WizardFive} path="/wFive"/>
<Route component={WizardSix} path="/wSix"/>
<Route component={WizardSeven} path="/wSeven"/>
<Route component={WizardEight} path="/wEight"/>
<Route component={WizardNine} path="/wNine"/>
<Route component={WizardTen} path="/wTen"/>
<Route component={WizardEleven} path="/wEleven"/>
<Route component={Finish} path='/finish'/>
</Switch>
)
If you noticed the app is no longer working, this is normal. We are restructuring the entire application. We can fix the errors by going into src/App.js
and modifying how we are using router
. Since it no longer a function, we take to remove the invocation and arguments.
render() {
return (
<div>
{ router }
</div>
);
}
The application should now render correctly again.
Solution
src/router.js
import React from 'react';
import WizardOne from './components/WizardOne/WizardOne';
import WizardTwo from './components/WizardTwo/WizardTwo';
import WizardThree from './components/WizardThree/WizardThree';
import WizardFour from './components/WizardFour/WizardFour';
import WizardFive from './components/WizardFive/WizardFive';
import WizardSix from './components/WizardSix/WizardSix';
import WizardSeven from './components/WizardSeven/WizardSeven';
import WizardEight from './components/WizardEight/WizardEight';
import WizardNine from './components/WizardNine/WizardNine';
import WizardTen from './components/WizardTen/WizardTen';
import WizardEleven from './components/WizardEleven/WizardEleven';
import Finish from './components/Finish/Finish';
import NextBtn from './components/NextBtn/NextBtn';
import { Switch, Route } from 'react-router-dom';
export default (
<Switch>
<Route component={NextBtn} exact path= '/'/>
<Route component={WizardOne} path='/wOne'/>
<Route component={WizardTwo} path="/wTwo"/>
<Route component={WizardThree} path="/wThree"/>
<Route component={WizardFour} path="/wFour"/>
<Route component={WizardFive} path="/wFive"/>
<Route component={WizardSix} path="/wSix"/>
<Route component={WizardSeven} path="/wSeven"/>
<Route component={WizardEight} path="/wEight"/>
<Route component={WizardNine} path="/wNine"/>
<Route component={WizardTen} path="/wTen"/>
<Route component={WizardEleven} path="/wEleven"/>
<Route component={Finish} path='/finish'/>
</Switch>
)
src/App.js
import React, { Component } from 'react';
import './App.css';
import router from './router'
import { HashRouter } from 'react-router-dom';
class App extends Component {
constructor(){
super()
this.state = {
loanType: 'Home Purchase',
propertyType: 'Single Family Home',
propToBeUsedOn: '',
city: '',
found: "false",
realEstateAgent: "false",
downPayment: 0,
cost: 0,
credit: '',
history: '',
addressOne: '',
addressTwo: '',
addressThree: '',
firstName: '',
lastName: '',
email: ''
}
this.handleChangeLoanType = this.handleChangeLoanType.bind(this);
this.handleChangePropertyType = this.handleChangePropertyType.bind(this);
this.handleChangePropertyToBeUsedOn = this.handleChangePropertyToBeUsedOn.bind(this);
this.handleChangeCity = this.handleChangeCity.bind(this);
this.handleChangeFoundFalse = this.handleChangeFoundFalse.bind(this);
this.handleChangeFoundTrue = this.handleChangeFoundTrue.bind(this);
this.handleChangeRealEstateAgentTrue = this.handleChangeRealEstateAgentTrue.bind(this);
this.handleChangeRealEstateAgentFalse = this.handleChangeRealEstateAgentFalse.bind(this);
this.handleChangeUpdateDownPayment = this.handleChangeUpdateDownPayment.bind(this);
this.handleChangeUpdateCost = this.handleChangeUpdateCost.bind(this);
this.handleChangeCreditE = this.handleChangeCreditE.bind(this);
this.handleChangeCreditG = this.handleChangeCreditG.bind(this);
this.handleChangeCreditF = this.handleChangeCreditF.bind(this);
this.handleChangeCreditP = this.handleChangeCreditP.bind(this);
this.handleChangeUpdateHistory = this.handleChangeUpdateHistory.bind(this);
this.handleChangeAddressOne = this.handleChangeAddressOne.bind(this);
this.handleChangeAddressTwo = this.handleChangeAddressTwo.bind(this);
this.handleChangeAddressThree = this.handleChangeAddressThree.bind(this);
this.handleChangeFirstName = this.handleChangeFirstName.bind(this);
this.handleChangeLastName = this.handleChangeLastName.bind(this);
this.handleChangeEmail = this.handleChangeEmail.bind(this);
}
handleChangeLoanType(event) {
this.setState({loanType : event.target.value});
}
handleChangePropertyType(event) {
this.setState({propertyType : event.target.value});
}
handleChangePropertyToBeUsedOn(event){
this.setState({propToBeUsedOn : event.target.value})
}
handleChangeCity(event){
this.setState({city : event.target.value});
}
handleChangeFoundTrue(event){
this.setState({found : "true"});
}
handleChangeFoundFalse(event){
this.setState({found : "false"});
}
handleChangeRealEstateAgentTrue(){
this.setState({realEstateAgent : "true"});
}
handleChangeRealEstateAgentFalse(){
this.setState({realEstateAgent : "false"});
}
handleChangeUpdateDownPayment(event){
this.setState({downPayment : event.target.value})
}
handleChangeUpdateCost(event){
this.setState({cost: event.target.value});
}
handleChangeCreditE(){
this.setState({credit: 'Excellent'})
}
handleChangeCreditG(){
this.setState({credit: 'Good'})
}
handleChangeCreditF(){
this.setState({credit: 'Fair'})
}
handleChangeCreditP(){
this.setState({credit: 'Poor'})
}
handleChangeUpdateHistory(event){
this.setState({history: event.target.value})
}
handleChangeAddressOne(event){
this.setState({addressOne: event.target.value})
}
handleChangeAddressTwo(event){
this.setState({addressTwo: event.target.value})
}
handleChangeAddressThree(event){
this.setState({addressThree: event.target.value})
}
handleChangeFirstName(event){
this.setState({firstName : event.target.value})
}
handleChangeLastName(event){
this.setState({lastName: event.target.value})
}
handleChangeEmail(event){
this.setState({email: event.target.value})
}
render() {
return (
<div>
<HashRouter>
{ router }
</HashRouter>
</div>
);
}
}
export default App;
Step 4
Summary
In this step, I’ll be removing the state and handler methods from App.js
. That’s because we no longer need either. Instead, all of our wizard steps (components) will connect to the redux store separately, and we don’t need to track state in App.js
, just for the sake of passing it down as props.
Instructions
- Open
src/App.js
. - In the App component, delete the constructor and state.
- Delete all the handler methods.
- In the return statement of
render()
, delete everything but thediv
with the router.
Solution
src/App.js
import React, { Component } from 'react';
import './App.css';
import router from './router';
import { HashRouter } from 'react-router-dom';
class App extends Component {
render() {
return (
<div>
<HashRouter>
{ router }
</HashRouter>
</div>
);
}
}
export default App;
Step 5
Summary
Let’s begin connecting our views. I’ll start with the Eleventh view. I chose the Eleventh view because as we start hooking our views up with redux
, I’ll be able to see the data getting to where it needs to end up.
Instructions
- Open
src/components/WizardEleven/WizardEleven.js
. - Import
connect
fromreact-redux
- Connect the component to the
redux store
.- Instead of
returning
the entire state inmapStateToProps
, return only the properties the component needs:-
Properties
loanType, propertyType, city, propToBeUsedOn, found, realEstateAgent, cost, downPayment, credit, history, addressOne, addressTwo, addressThree, firstName, lastName, email
-
You may be scratching your head as to why we are using these exact propeties. When we setup the reducer later on, these will be the names of the properties the
redux
store will be managing.
-
- Instead of
Detailed Instructions
Let’s begin by opening src/components/WizardEleven/WizardEleven.js
and importing connect
from react-redux
.
import { connect } from 'react-redux';
Before we create our connect
statement, let’s make a mapStateToProps
function. Instead of passing the entire state from the store, we are going to pick very specific properties. The list of properties I’ll need are listed in the instructions above.
function mapStateToProps( state ) {
return{
loanType: state.loanType,
propertyType: state.propertyType,
city: state.city,
propToBeUsedOn: state.propToBeUsedOn,
found: state.found,
realEstateAgent: state.realEstateAgent,
cost: state.cost,
downPayment: state.downPayment,
credit: state.credit,
history: state.history,
addressOne: state.addressOne,
addressTwo: state.addressTwo,
addressThree: state.addressThree,
firstName: state.firstName,
lastName: state.lastName,
email: state.email
};
}
export default WizardEleven;
Now that we have the parts of state we want, we can create our connect
statement.
function mapStateToProps( state ) {
return {
loanType: state.loanType,
propertyType: state.propertyType,
city: state.city,
propToBeUsedOn: state.propToBeUsedOn,
found: state.found,
realEstateAgent: state.realEstateAgent,
cost: state.cost,
downPayment: state.downPayment,
credit: state.credit,
history: state.history,
addressOne: state.addressOne,
addressTwo: state.addressTwo,
addressThree: state.addressThree,
firstName: state.firstName,
lastName: state.lastName,
email: state.email
};
}
export default connect( mapStateToProps )( WizardEleven );
Solution
src/components/WizardEleven/WizardEleven.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
class WizardEleven extends Component {
render(){
return(
<div className="parent-div">
<div className="vert-align">
<p>Here is an overview of your form:</p>
<div >
<div className="overarching-div">
<div className="form" >Name:
<p className="p2">
{this.props.firstName} {this.props.lastName}
</p>
</div>
</div>
<div className="overarching-div">
<div className="form" >Email:
<p className="p2">
{this.props.email}
</p>
</div>
</div>
<div className="overarching-div">
<div className="form" >What type of loan will you be needing?:
<p className="p2">
{this.props.loanType}
</p>
</div>
</div>
<div className="overarching-div">
<div className="form" >What type of property are you purchasing?:
<p className="p2">
{this.props.propertyType}
</p>
</div>
</div>
<div className="overarching-div">
<div className="form" >In what city will the property be located?:
<p className="p2">
{this.props.city}
</p>
</div>
</div>
<div className="overarching-div">
<div className="form" >Type of property the loan is applied to:
<p className="p2">
{this.props.propToBeUsedOn}
</p>
</div>
</div>
<div className="overarching-div">
<div className="form" >Have you already found your new home?:
<p className="p2">
{this.props.found}
</p>
</div>
</div>
<div className="overarching-div">
<div className="form" >Currently working with a real estate agent?:
<p className="p2">
{this.props.realEstateAgent}
</p>
</div>
</div>
<div className="overarching-div">
<div className="form" >Estimated purchase price of the home:
<p className="p2">
{this.props.cost}
</p>
</div>
</div>
<div className="overarching-div">
<div className="form" >Down payment:
<p className="p2">
{this.props.downPayment}
</p>
</div>
</div>
<div className="overarching-div">
<div className="form" >Credit score:
<p className="p2">
{this.props.credit}
</p>
</div>
</div>
<div className="overarching-div">
<div className="form" >Bankruptcy history:
<p className="p2">
{this.props.history}
</p>
</div>
</div>
<div className="overarching-div">
<div className="form" >Current Address:
<p className="p2">
{this.props.addressOne} <br />
{this.props.addressTwo} <br />
{this.props.addressThree}
</p>
</div>
</div>
</div>
</div>
<div className="row">
<Link to="/finish"> <button>Send</button></Link>
<Link to="/"> <button>Start Again</button></Link>
</div>
</div>
)
}
}
function mapStateToProps( state ) {
return {
loanType: state.loanType,
propertyType: state.propertyType,
city: state.city,
propToBeUsedOn: state.propToBeUsedOn,
found: state.found,
realEstateAgent: state.realEstateAgent,
cost: state.cost,
downPayment: state.downPayment,
credit: state.credit,
history: state.history,
addressOne: state.addressOne,
addressTwo: state.addressTwo,
addressThree: state.addressThree,
firstName: state.firstName,
lastName: state.lastName,
email: state.email
};
}
export default connect( mapStateToProps )( WizardEleven );
Step 6
Summary
Now let’s take a look at our first view: src/components/WizardOne/WizardOne.js
. It looks like we need to be able to update the loanType
and propertyType
items on state. In redux, in order to update something, we need to have a reducer and action creators.
In this step, I’ll start creating our store’s reducer and the action creators to update loanType
and propertyType
.
Instructions
- Open
src/ducks/reducer.js
. - Create an
initialState
object, at the very top of the file, with the following properties:-
Initial State Properties
loanType: 'Home Purchase', propertyType: 'Single Family Home', city: '', propToBeUsedOn: '', found: "false", realEstateAgent: "false", cost: 0, downPayment: 0, credit: '', history: '', addressOne: '', addressTwo: '', addressThree: '', firstName: '', lastName: '', email: ''
-
- Modify the
reducer
function to have a state and action parameter.- The
state
parameter should default toinitialState
.
- The
- Create two action types in between
initialState
and thereducer
function.- The first action type should equal:
"UPDATE_LOAN_TYPE"
. - The second action type should equal:
"UPDATE_PROPERTY_TYPE"
.
- The first action type should equal:
- Create two action creators in between the
reducer
function and theexport default
statement.- The first action creator should have a type of
UPDATE_LOAN_TYPE
.- This action creator should have a parameter called
loanType
. - This action creator should have a payload that equals
loanType
.
- This action creator should have a parameter called
- The second action creator should have a type of
UPDATE_PROPERTY_TYPE
.- This action creator should have a parameter called
property
. - This action creator should have a payload that equals
property
.
- This action creator should have a parameter called
- The first action creator should have a type of
- Modify the
reducer
function to use aswitch
statement on theaction.type
.- Create a
case
forUPDATE_LOAN_TYPE
and update state with the new loan type. - Create a
case
forUPDATE_PROPERTY_TYPE
and update state with the new property type. - Create a
default case
that returns state.
- Create a
Detailed Instructions
Let’s begin by opening src/ducks/reducer.js
. Our store will need an initial state when it loads for the first time. Let’s create a constant variable called initialState
that will have all of our state’s initial values. The property list is listed above in the instructions.
const initialState = {
loanType: 'Home Purchase',
propertyType: 'Single Family Home',
city: '',
propToBeUsedOn: '',
found: false,
realEstateAgent: "false",
cost: 0,
downPayment: 0,
credit: '',
history: '',
addressOne: '',
addressTwo: '',
addressThree: '',
firstName: '',
lastName: '',
email: ''
};
Now that we have an initial state we can update our reducer
function to have a state
and action
parameter. Using es6
default parameters we can default the state
parameter to initialState
. This will happen when the store is first created.
function reducer( state = initialState, action ) {
}
Before we create the action creators our store needs to determine how to update state, we need to create our action types. I’ll put these action types in between our initialState
and reducer
function. I’ll need two types for this step. One type for updating the loan type and one type for updating the property type.
const UPDATE_LOAN_TYPE = "UPDATE_LOAN_TYPE";
const UPDATE_PROPERTY_TYPE = "UPDATE_PROPERTY_TYPE";
Now that we have our two action types we can create action creators that use them. All an action creator does is return an object with a type
and payload
property. The payload
will equal the value of the parameter in this case. The action creator for loan type will have a loanType
parameter and the action creator for property type will have a property
parameter. We also export these action creators so other components can use them. Let’s add them under the reducer
function.
export function updateLoanType( loanType ){
return {
type: UPDATE_LOAN_TYPE,
payload: loanType
}
}
export function updatePropertyType( property ) {
return {
type: UPDATE_PROPERTY_TYPE,
payload: property
}
}
The last thing we need to do is update the reducer
function to use a switch
statement on the action.type
. This is how our reducer
will determine which part of state to update. Since we need to keep state immutable
we will make use of Object.assign
. Let’s start by adding a switch
statement to our reducer. The default case
for this switch should just return state
.
function reducer( state = initialState, action ) {
switch( action.type ) {
default: return state;
}
}
To add our action types to our reducer all we have to do is: case actionTypeVariableGoesHere
. I’ll then use Object.assign
to get the previous value of state and update its loanType
or propertyType
property to the value on the payload.
function reducer( state = initialState, action ) {
switch( action.type ) {
case UPDATE_LOAN_TYPE:
return Object.assign( {}, state, { loanType: action.payload } );
case UPDATE_PROPERTY_TYPE:
return Object.assign( {}, state, { propertyType: action.payload } );
default: return state;
}
}
Solution
src/ducks/reducer.js
const initialState = {
loanType: 'Home Purchase',
propertyType: 'Single Family Home',
city: '',
propToBeUsedOn: '',
found: false,
realEstateAgent: "false",
cost: 0,
downPayment: 0,
credit: '',
history: '',
addressOne: '',
addressTwo: '',
addressThree: '',
firstName: 'aa',
lastName: '',
email: ''
}
const UPDATE_LOAN_TYPE = "UPDATE_LOAN_TYPE";
const UPDATE_PROPERTY_TYPE = 'UPDATE_PROPERTY_TYPE';
function reducer( state = initialState, action ){
switch( action.type ){
case UPDATE_LOAN_TYPE:
return Object.assign( {}, state, { loanType: action.payload } );
case UPDATE_PROPERTY_TYPE:
return Object.assign( {}, state, { propertyType: action.payload } );
default: return state;
}
}
export function updateLoanType( loanType ){
return {
type: UPDATE_LOAN_TYPE,
payload: loanType
}
}
export function updatePropertyType( property ) {
return {
type: UPDATE_PROPERTY_TYPE,
payload: property
}
}
export default reducer;
Step 7
Summary
In this step, we will connect src/components/WizardOne/WizardOne.js
to the store and configure the component to use the action creators we have created so far.
Instructions
- Open
src/components/WizardOne/WizardOne.js
. - Import
connect
fromreact-redux
. - Import the
updateLoanType
andupdatePropertyType
action creators fromsrc/ducks/reducer.js
.- Hint: Use destructuring.
- Modify the
export default
statement to useconnect
.- Use
mapStateToProps
to return the only two parts ofstate
it will need. - Use a second parameter on the
connect
statement that passes in the action creators.
- Use
- Modify the two
onChange
events to use the action creators.- Hint: Both action creators need an argument.
Detailed Instructions
Let’s begin by opening src/components/WizardOne/WizardOne.js
and importing connect
and the action creators we have created so far.
import { connect } from 'react-redux';
import { updateLoanType, updatePropertyType } from '../../ducks/reducer';
Now that we have these, we can modify the export default
statement to connect
to our store. In this case, I’ll only need two properties from state
and I’ll also be passing in the action creators. When we pass in the action creators into our connect
statement it wraps them in a dispatch
function. This allows our component to just call the action creator. If we didn’t do it this way, we would have to import dispatch
and call dispatch
with our action creator as an argument.
Since this component has select statements for a loan type and property type, we will want the loanType
and propertyType
from state
.
function mapStateToProps( state ) {
const { loanType, propertyType } = state;
return {
loanType,
propertyType
};
}
export default connect( mapStateToProps, { updateLoanType, updatePropertyType } )( WizardOne );
We can then destructure our action creators off of props
. It is imperative that you call your action creators off of props
otherwise the function call will never make it to the store
.
render() {
const { updateLoanType, updatePropertyType } = this.props;
}
Now that our component is connected to the store
and our action creators are destructured off of props
, we can modify the onChange
events to call the action creators. Remember that each action creator needs one argument. This argument will be the value that replaces the property’s value on state
. We can capture the event and pass in the event’s target value as the argument.
<select onChange={ ( e ) => updateLoanType( e.target.value ) }>
<option type="text" value="Home Purchase" >Home Purchase</option>
<option type="text" value="Refinance" >Refinance</option>
<option type="text" value="Home Equity" >Home Equity loan/line</option>
</select> <br/>
<select onChange={ ( e ) => updatePropertyType( e.target.value ) }>
<option value="Single Family Home">Single Family Home</option>
<option value="Town Home">Townhome</option>
<option value="Condo">Condo</option>
<option value="Multi Family Home">Multi Family Dwelling</option>
<option value="Mobile Home">Mobile Home</option>
</select>
Solution
src/components/WizardOne/WizardOne.js
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import { connect } from 'react-redux';
import { updateLoanType, updatePropertyType } from '../../ducks/reducer';
class WizardOne extends Component {
render(){
const { updateLoanType, updatePropertyType } = this.props;
return(
<div className="parent-div">
<div className="vert-align">
<p>What type of loan will you be needing?</p> <br />
<select onChange={ ( e ) => updateLoanType( e.target.value ) }>
<option type="text" value="Home Purchase" >Home Purchase</option>
<option type="text" value="Refinance" >Refinance</option>
<option type="text" value="Home Equity" >Home Equity loan/line</option>
</select> <br/>
<p>What type of property are you purchasing?</p> <br />
<select onChange={ ( e ) => updatePropertyType( e.target.value ) }>
<option value="Single Family Home">Single Family Home</option>
<option value="Town Home">Townhome</option>
<option value="Condo">Condo</option>
<option value="Multi Family Home">Multi Family Dwelling</option>
<option value="Mobile Home">Mobile Home</option>
</select>
<Link to="/wTwo"><button className="margin-btn"> Next </button></Link>
</div>
</div>
)
}
}
function mapStateToProps( state ) {
const { loanType, propertyType } = state;
return {
loanType,
propertyType
};
}
export default connect( mapStateToProps, { updateLoanType, updatePropertyType } )( WizardOne );
Step 8
Summary
In this step, we will update the reducer to handle modifying the city on state. We will also configure the src/components/WizardTwo/WizardTwo.js
to connect to the store and use an action creator to update the city on state.
Instructions
- Open
src/ducks/reducer.js
. - Create an action type for
UPDATE_CITY
. - Create an action creator called
updateCity
.- This action creator should use a parameter called
city
.
- This action creator should use a parameter called
- Add an
UPDATE_CITY
case to the reducer that updatescity
.- Remember to keep state immutable.
- Open
src/components/WizardTwo/WizardTwo.js
. - Import
connect
fromreact-redux
. - Import
updateCity
fromsrc/ducks/reducer.js
. - Modify the
export default
statement to use connect.mapStateToProps
should only return one property from state.updateCity
should be passed in as a second parameter.
- Modify the
onChange
event to callupdateCity
.- Remember this action creator has one parameter.
Detailed Instructions
Let’s begin by opening src/ducks/reducer.js
and creating an UPDATE_CITY
action type.
const UPDATE_CITY = 'UPDATE_CITY';
Then we can create an updateCity
action creator that uses UPDATE_CITY
as its type
. This action creator should have a parameter called city
. We will use the value of city
for the payload property.
export function updateCity( city ) {
return {
type: UPDATE_CITY,
payload: city
}
}
Now let’s add an UPDATE_CITY
case to the reducer. In this case, the reducer should update the value of city
on state using the value set on the action’s payload. Remember that we need to keep state immutable, so I’ll make use of Object.assign
.
case UPDATE_CITY:
return Object.assign( {}, state, { city: action.payload } );
Our store now has everything it needs to update the state
‘s city. Let’s now implement this into src/components/WizardTwo/WizardTwo.js
. Open this file and import connect
from react-redux
and import updateCity
from src/ducks/reducer.js
.
import { connect } from 'react-redux';
import { updateCity } from '../../ducks/reducer.js';
Before we modify our component to connect
to the store, let’s create a mapStateToProps
function. Since the second screen of the wizard process only asks the user for their city, we only need city from the store
‘s state.
function mapStateToProps( state ) {
const { city } = state;
return {
city
};
}
export default WizardTwo;
Now that we have a mapStateToProps
function, let’s modify the export default
statement to use connect
. Remember that we should also include updateCity
as a second parameter. This will allow us to call updateCity
off of props without having to worry about dispatch
.
export default connect( mapStateToProps, { updateCity } )( WizardTwo );
Now that our component is connected to the store, we can update the onChange
event to call updateCity
instead. You can either deconstruct updateCity
off of props or call this.props.updateCity
.
<input placeholder="city name" type="text" onChange={ ( e ) => updateCity( e.target.value ) } />
Solution
src/ducks/reducer.js
const initialState = {
loanType: 'Home Purchase',
propertyType: 'Single Family Home',
city: '',
propToBeUsedOn: '',
found: false,
realEstateAgent: "false",
cost: 0,
downPayment: 0,
credit: '',
history: '',
addressOne: '',
addressTwo: '',
addressThree: '',
firstName: 'aa',
lastName: '',
email: ''
}
const UPDATE_LOAN_TYPE = "UPDATE_LOAN_TYPE";
const UPDATE_PROPERTY_TYPE = 'UPDATE_PROPERTY_TYPE';
const UPDATE_CITY = "UPDATE_CITY";
function reducer( state = initialState, action ) {
switch( action.type ){
case UPDATE_LOAN_TYPE:
return Object.assign( {}, state, { loanType: action.payload } );
case UPDATE_PROPERTY_TYPE:
return Object.assign( {}, state, { propertyType: action.payload } );
case UPDATE_CITY:
return Object.assign( {}, state, { city: action.payload } );
default: return state;
}
}
export function updateLoanType( loanType ){
return {
type: UPDATE_LOAN_TYPE,
payload: loanType
};
}
export function updatePropertyType( property ) {
return {
type: UPDATE_PROPERTY_TYPE,
payload: property
};
}
export function updateCity( city ) {
return {
type: UPDATE_CITY,
payload: city
};
}
export default reducer;
src/components/WizardTwo/WizardTwo.js
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import { connect } from "react-redux";
import { updateCity } from '../../ducks/reducer';
class WizardTwo extends Component {
render() {
const { updateCity } = this.props;
return(
<div className="parent-div">
<div className="vert-align">
<p>In what city will the property be located?</p><br />
<input placeholder="city name" type="text" onChange={ ( e ) => updateCity( e.target.value ) } />
<Link to="/wThree"><button className="wTwo-btn"> Next </button></Link>
</div>
</div>
)
}
}
function mapStateToProps( state ) {
const { city } = state;
return {
city
};
}
export default connect( mapStateToProps, { updateCity } )( WizardTwo );
Step 9
Summary
In this step, we will update the reducer to handle modifying the propToBeUsedOn
on state. We will also configure src/components/WizardThree/WizardThree.js
to connect to the store and use an action creator to update propToBeUsedOn
on state.
Instructions
- Open
src/ducks/reducer.js
. - Create an action type for
UPDATE_PROP
. - Create an action creator called
updateProp
.- This action creator should use a parameter called
prop
.
- This action creator should use a parameter called
- Add an
UPDATE_PROP
case to the reducer that updatespropToBeUsedOn
.- Remember to keep state immutable.
- Open
src/components/WizardThree/WizardThree.js
. - Import
connect
fromreact-redux
. - Import
updateProp
fromsrc/ducks/reducer.js
. - Modify the
export default
statement to use connect.mapStateToProps
should only return one property from state.updateProp
should be passed in as a second parameter.
- Modify the
onClick
events to callupdateProp
.- Remember this action creator has one parameter.
Detailed Instructions
Let’s begin by opening src/ducks/reducer.js
and creating an UPDATE_PROP
action type.
const UPDATE_PROP = 'UPDATE_PROP';
Then we can create an updateProp
action creator that uses UPDATE_PROP
as its type
. This action creator should have a parameter called prop
. We will use the value of prop
for the payload property.
export function updateProp( prop ) {
return {
type: UPDATE_PROP,
payload: prop
}
}
Now let’s add an UPDATE_PROP
case to the reducer. In this case, the reducer should update the value of propToBeUsedOn
on state using the value set on the action’s payload. Remember that we need to keep state immutable, so I’ll make use of Object.assign
.
case UPDATE_PROP:
return Object.assign( {}, state, { propToBeUsedOn: action.payload } );
Our store now has everything it needs to update the state
‘s propToBeUsedOn
property. Let’s now implement this into src/components/WizardThree/WizardThree.js
. Open this file and import connect
from react-redux
and import updateProp
from src/ducks/reducer.js
.
import { connect } from 'react-redux';
import { updateProp } from '../../ducks/reducer.js';
Before we modify our component to connect
to the store, let’s create a mapStateToProps
function. Since the third screen of the wizard process only asks the user for their property type, we only need propToBeUsedOn
from the store
‘s state.
function mapStateToProps( state ) {
const { propToBeUsedOn } = state;
return {
propToBeUsedOn
};
}
export default WizardThree;
Now that we have a mapStateToProps
function, let’s modify the export default
statement to use connect
. Remember that we should also include updateProp
as a second parameter. This will allow us to call updateProp
off of props without having to worry about dispatch
.
export default connect( mapStateToProps, { updateProp } )( WizardThree );
Now that our component is connected to the store, we can update the onClick
events to call updateProp
instead. You can either deconstruct updateProp
off of props or call this.props.updateProp
. Since the button elements have a value, you can capture the event and pass in the event’s target value.
<button value="primaryHome" onClick={ ( e ) => updateProp( e.target.value ) }>Primary Home</button>
<button value="rentalProperty" onClick={ ( e ) => updateProp( e.target.value ) }>Rental Property</button>
<button value="secondaryHome" onClick={ ( e ) => updateProp( e.target.value ) }>Secondary Home</button>
Solution
src/ducks/reducer.js
const initialState = {
loanType: 'Home Purchase',
propertyType: 'Single Family Home',
city: '',
propToBeUsedOn: '',
found: false,
realEstateAgent: "false",
cost: 0,
downPayment: 0,
credit: '',
history: '',
addressOne: '',
addressTwo: '',
addressThree: '',
firstName: 'aa',
lastName: '',
email: ''
}
const UPDATE_LOAN_TYPE = "UPDATE_LOAN_TYPE";
const UPDATE_PROPERTY_TYPE = 'UPDATE_PROPERTY_TYPE';
const UPDATE_CITY = "UPDATE_CITY";
const UPDATE_PROP = "UPDATE_PROP";
function reducer( state = initialState, action ) {
console.log('REDUCER HIT: Action ->', action );
switch( action.type ){
case UPDATE_LOAN_TYPE:
return Object.assign( {}, state, { loanType: action.payload } );
case UPDATE_PROPERTY_TYPE:
return Object.assign( {}, state, { propertyType: action.payload } );
case UPDATE_CITY:
return Object.assign( {}, state, { city: action.payload } );
case UPDATE_PROP:
return Object.assign( {}, state, { propToBeUsedOn: action.payload } );
default: return state;
}
}
export function updateLoanType( loanType ){
return {
type: UPDATE_LOAN_TYPE,
payload: loanType
};
}
export function updatePropertyType( property ) {
return {
type: UPDATE_PROPERTY_TYPE,
payload: property
};
}
export function updateCity( city ) {
return {
type: UPDATE_CITY,
payload: city
};
}
export function updateProp( prop ) {
return {
type: UPDATE_PROP,
payload: prop
};
}
export default reducer;
src/components/WizardThree/WizardThree.js
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import { connect } from 'react-redux';
import { updateProp } from '../../ducks/reducer';
class WizardThree extends Component {
render() {
const { updateProp } = this.props;
return (
<div className="parent-div">
<div className="vert-align">
<p> What property are you looking to use the loan on? </p><br />
<div className="row">
<Link to="/wFour">
<button value="primaryHome" onClick={ ( e ) => updateProp( e.target.value ) }>Primary Home</button>
</Link>
<Link to="/wFour">
<button value="rentalProperty" onClick={ ( e ) => updateProp( e.target.value ) }>Rental Property</button>
</Link>
<Link to="/wFour">
<button value="secondaryHome" onClick={ ( e ) => updateProp( e.target.value ) }>Secondary Home</button>
</Link>
</div>
</div>
</div>
)
}
}
function mapStateToProps( state ) {
const { propToBeUsedOn } = state;
return {
propToBeUsedOn
};
}
export default connect( mapStateToProps, { updateProp } )( WizardThree );
Step 10
Summary
In this step, we will update the reducer to handle modifying the found
on state. We will also configure src/components/WizardFour/WizardFour.js
to connect to the store and use an action creator to update found
on state.
Instructions
- Open
src/ducks/reducer.js
. - Create an action type for
UPDATE_FOUND
. - Create an action creator called
updateFound
.- This action creator should use a parameter called
found
.
- This action creator should use a parameter called
- Add an
UPDATE_FOUND
case to the reducer that updatesfound
.- Remember to keep state immutable.
- Open
src/components/WizardFour/WizardFour.js
. - Import
connect
fromreact-redux
. - Import
updateFound
fromsrc/ducks/reducer.js
. - Modify the
export default
statement to use connect.mapStateToProps
should only return one property from state.updateFound
should be passed in as a second parameter.
- Modify the
onClick
events to callupdateFound
.- Remember this action creator has one parameter.
Detailed Instructions
Let’s begin by opening src/ducks/reducer.js
and creating an UPDATE_FOUND
action type.
const UPDATE_FOUND = 'UPDATE_FOUND';
Then we can create an updateFound
action creator that uses UPDATE_FOUND
as its type
. This action creator should have a parameter called found
. We will use the value of found
for the payload property.
export function updateFound( found ) {
return {
type: UPDATE_FOUND,
payload: found
}
}
Now let’s add an UPDATE_FOUND
case to the reducer. In this case, the reducer should update the value of found
on state using the value set on the action’s payload. Remember that we need to keep state immutable, so I’ll make use of Object.assign
.
case UPDATE_FOUND:
return Object.assign( {}, state, { found: action.payload } );
Our store now has everything it needs to update the state
‘s found
property. Let’s now implement this into src/components/WizardFour/WizardFour.js
. Open this file and import connect
from react-redux
and import updateFound
from src/ducks/reducer.js
.
import { connect } from 'react-redux';
import { updateFound } from '../../ducks/reducer.js';
Before we modify our component to connect
to the store, let’s create a mapStateToProps
function. Since the fourth screen of the wizard process only asks the user if they have found their property, we only need found
from the store
‘s state.
function mapStateToProps( state ) {
const { found } = state;
return {
found
};
}
export default WizardFour;
Now that we have a mapStateToProps
function, let’s modify the export default
statement to use connect
. Remember that we should also include updateFound
as a second parameter. This will allow us to call updateFound
off of props without having to worry about dispatch
.
export default connect( mapStateToProps, { updateFound } )( WizardFour );
Now our component is connected to the redux store
, let’s access the function we need to change state on the Link element.
- Set up the first Link element’s
onClick
function equal to{(e)=>this.props.updateFound("True")}
. - Set up the second Link element’s
onClick
function equal to{(e)=>this.props.updateFound("False")}
. - Because we’ve connected to
redux
, the updateFound function is now on props for this component.
<Link to="/wFive"><button onClick={ (e)=>this.props.updateFound("True") }>Yes</button></Link>
<Link to="/wFive"><button onClick={ (e)=>this.props.updateFound("False") }>No </button></Link>
Solution
src/ducks/reducer.js
const initialState = {
loanType: 'Home Purchase',
propertyType: 'Single Family Home',
city: '',
propToBeUsedOn: '',
found: false,
realEstateAgent: "false",
cost: 0,
downPayment: 0,
credit: '',
history: '',
addressOne: '',
addressTwo: '',
addressThree: '',
firstName: 'aa',
lastName: '',
email: ''
}
const UPDATE_LOAN_TYPE = "UPDATE_LOAN_TYPE";
const UPDATE_PROPERTY_TYPE = 'UPDATE_PROPERTY_TYPE';
const UPDATE_CITY = "UPDATE_CITY";
const UPDATE_PROP = "UPDATE_PROP";
const UPDATE_FOUND = "UPDATE_FOUND";
function reducer( state = initialState, action ) {
console.log('REDUCER HIT: Action ->', action );
switch( action.type ){
case UPDATE_LOAN_TYPE:
return Object.assign( {}, state, { loanType: action.payload } );
case UPDATE_PROPERTY_TYPE:
return Object.assign( {}, state, { propertyType: action.payload } );
case UPDATE_CITY:
return Object.assign( {}, state, { city: action.payload } );
case UPDATE_PROP:
return Object.assign( {}, state, { propToBeUsedOn: action.payload } );
case UPDATE_FOUND:
return Object.assign( {}, state, { found: action.payload } );
default: return state;
}
}
export function updateLoanType( loanType ){
return {
type: UPDATE_LOAN_TYPE,
payload: loanType
};
}
export function updatePropertyType( property ) {
return {
type: UPDATE_PROPERTY_TYPE,
payload: property
};
}
export function updateCity( city ) {
return {
type: UPDATE_CITY,
payload: city
};
}
export function updateProp( prop ) {
return {
type: UPDATE_PROP,
payload: prop
};
}
export function updateFound( found ) {
return {
type: UPDATE_FOUND,
payload: found
};
}
export default reducer;
src/components/WizardFour/WizardFour.js
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import { connect } from 'react-redux';
import { updateFound } from '../../ducks/reducer';
class WizardFour extends Component {
render() {
const { updateFound } = this.props;
return (
<div className="parent-div">
<div className="vert-align">
<p>Have you already found your new home?</p><br />
<div className="row">
<Link to="/wFive">
<button onClick={ ( e ) => updateFound( true ) }>Yes</button>
</Link>
<Link to="/wFive">
<button onClick={ ( e ) => updateFound( false ) }>No</button>
</Link>
</div>
</div>
</div>
)
}
}
function mapStateToProps( state ) {
const { found } = state;
return {
found
};
}
export default connect( mapStateToProps, { updateFound } )( WizardFour );
Step 11 – Challenge
Summary
In this step, we will complete the rest of the reducer for updating the remaining properties on state. We want this step to be a challenge for you, meaning there will not be any guided instructions. Try to complete this step without looking at any previous steps. If you get stuck, try looking back at the previous three steps.
Instructions
- Open
src/ducks/reducer.js
. - Create an action type for updating the following state properties:
realEstateAgent
cost
downPayment
credit
history
addressOne
addressTwo
addressThree
firstName
lastName
email
- Create an action creator for each property listed above.
- Update the reducer to have a case for each new action type.
- The case should update state with the value on the payload.
- Remember to keep state immutable.
Solution
src/ducks/reducer.js
const initialState = {
loanType: 'Home Purchase',
propertyType: 'Single Family Home',
city: '',
propToBeUsedOn: '',
found: false,
realEstateAgent: "false",
cost: 0,
downPayment: 0,
credit: '',
history: '',
addressOne: '',
addressTwo: '',
addressThree: '',
firstName: 'aa',
lastName: '',
email: ''
}
const UPDATE_LOAN_TYPE = "UPDATE_LOAN_TYPE";
const UPDATE_PROPERTY_TYPE = 'UPDATE_PROPERTY_TYPE';
const UPDATE_CITY = "UPDATE_CITY";
const UPDATE_PROP = "UPDATE_PROP";
const UPDATE_FOUND = "UPDATE_FOUND";
const UPDATE_AGENT = "UPDATE_AGENT";
const UPDATE_COST = "UPDATE_COST";
const UPDATE_DOWN_PAYMENT = "UPDATE_DOWN_PAYMENT";
const UPDATE_CREDIT = "UPDATE_CREDIT";
const UPDATE_HISTORY = "UPDATE_HISTORY";
const UPDATE_ADDRESS_1 = "UPDATE_ADDRESS_1";
const UPDATE_ADDRESS_2 = "UPDATE_ADDRESS_2";
const UPDATE_ADDRESS_3 = "UPDATE_ADDRESS_3";
const UPDATE_FIRST = "UPDATE_FIRST";
const UPDATE_LAST = "UPDATE_LAST";
const UPDATE_EMAIL = "UPDATE_EMAIL";
function reducer( state = initialState, action ) {
console.log('REDUCER HIT: Action ->', action );
switch( action.type ){
case UPDATE_LOAN_TYPE:
return Object.assign( {}, state, { loanType: action.payload } );
case UPDATE_PROPERTY_TYPE:
return Object.assign( {}, state, { propertyType: action.payload } );
case UPDATE_CITY:
return Object.assign( {}, state, { city: action.payload } );
case UPDATE_PROP:
return Object.assign( {}, state, { propToBeUsedOn: action.payload } );
case UPDATE_FOUND:
return Object.assign( {}, state, { found: action.payload } );
case UPDATE_AGENT:
return Object.assign( {}, state, { realEstateAgent: action.payload } );
case UPDATE_COST:
return Object.assign( {}, state, { cost: action.payload } );
case UPDATE_DOWN_PAYMENT:
return Object.assign( {}, state, { downPayment: action.payload } );
case UPDATE_CREDIT:
return Object.assign( {}, state, { credit: action.payload } );
case UPDATE_HISTORY:
return Object.assign( {}, state, { history: action.payload } );
case UPDATE_ADDRESS_1:
return Object.assign( {}, state, { addressOne: action.payload } );
case UPDATE_ADDRESS_2:
return Object.assign( {}, state, { addressTwo: action.payload } );
case UPDATE_ADDRESS_3:
return Object.assign( {}, state, { addressThree: action.payload } );
case UPDATE_FIRST:
return Object.assign( {}, state, { firstName: action.payload } );
case UPDATE_LAST:
return Object.assign( {}, state, { lastName: action.payload } );
case UPDATE_EMAIL:
return Object.assign( {}, state, { email: action.payload } );
default: return state;
}
}
export function updateLoanType( loanType ){
return {
type: UPDATE_LOAN_TYPE,
payload: loanType
};
}
export function updatePropertyType( property ) {
return {
type: UPDATE_PROPERTY_TYPE,
payload: property
};
}
export function updateCity( city ) {
return {
type: UPDATE_CITY,
payload: city
};
}
export function updateProp( prop ) {
return {
type: UPDATE_PROP,
payload: prop
};
}
export function updateFound( found ) {
return {
type: UPDATE_FOUND,
payload: found
};
}
export function updateAgent( agent ) {
return {
type: UPDATE_AGENT,
payload: agent
};
}
export function updateCost( cost ) {
return {
type: UPDATE_COST,
payload: cost
};
}
export function updateDownPayment( payment ) {
return {
type: UPDATE_DOWN_PAYMENT,
payload: payment
};
}
export function updateCredit( credit ) {
return {
type: UPDATE_CREDIT,
payload: credit
};
}
export function updateHistory( history ) {
return {
type: UPDATE_HISTORY,
payload: history
};
}
export function updateAddress1( address ) {
return {
type: UPDATE_ADDRESS_1,
payload: address
};
}
export function updateAddress2( address ) {
return {
type: UPDATE_ADDRESS_2,
payload: address
};
}
export function updateAddress3( address ) {
return {
type: UPDATE_ADDRESS_3,
payload: address
};
}
export function updateFirst( first ) {
return {
type: UPDATE_FIRST,
payload: first
};
}
export function updateLast( last ) {
return {
type: UPDATE_LAST,
payload: last
};
}
export function updateEmail( email ) {
return {
type: UPDATE_EMAIL,
payload: email
};
}
export default reducer;
Step 12 – Challenge
Summary
In this step, we will hook up the rest of the views to the store and modify the events to call our action creators. We want this step to be a challenge for you, meaning there will not be any guided instructions. Try to complete this step without looking at any previous steps. If you get stuck, try looking back steps eight through ten.
Instructions
Open the remaining wizard
components ( Wizard 5-10 ) and update them to connect to the store. Remember to use mapStateToProps
to grab only the property(s) that component is modifying. Also remember to pull in the action creator(s) from the reducer. Then modify the events in the component ( onChange
|| onClick
) to call the action creator(s).
Solution
src/components/WizardFive/WizardFive.js
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import { connect } from 'react-redux';
import { updateAgent } from '../../ducks/reducer';
class WizardFive extends Component {
render() {
const { updateAgent } = this.props;
return (
<div className="parent-div">
<div className="vert-align">
<p>Are you currently working with a real estate agent?</p> <br />
<div className="row">
<Link to="/wSix">
<button onClick={ () => updateAgent( true ) }>Yes</button>
</Link>
<Link to="/wSix">
<button onClick={ () => updateAgent( false ) }>No</button>
</Link>
</div>
</div>
</div>
)
}
}
function mapStateToProps( state ) {
const { realEstateAgent } = state;
return {
realEstateAgent
};
}
export default connect( mapStateToProps, { updateAgent } )( WizardFive );
src/components/WizardSix/WizardSix.js
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import { connect } from 'react-redux';
import { updateCost, updateDownPayment } from '../../ducks/reducer';
class WizardSix extends Component {
render() {
const { updateCost, updateDownPayment } = this.props;
return (
<div className="parent-div">
<div className="vert-align">
<p>What is the estimated purchase price?</p> <br />
<input type="text" placeholder="amount" onChange={ ( e ) => updateCost( e.target.value ) } /> <br />
<p>How much are you putting down as a down payment?</p> <br />
<input type="text" placeholder="amount" onChange={ ( e ) => updateDownPayment( e.target.value ) } />
<Link to="/wSeven">
<button className="margin-btn"> Next </button>
</Link>
</div>
</div>
)
}
}
function mapStateToProps( state ) {
const { cost, downPayment } = state;
return {
cost,
downPayment
};
}
export default connect( mapStateToProps, { updateCost, updateDownPayment } )( WizardSix );
src/components/WizardSeven/WizardSeven.js
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import { connect } from 'react-redux';
import { updateCredit } from '../../ducks/reducer';
class WizardSeven extends Component {
render() {
const { updateCredit } = this.props;
return (
<div className="parent-div">
<div className="vert-align">
<p>Estimate your credit score</p> <br />
<div className="row">
<Link to="/wEight">
<button onClick={ () => updateCredit('Excellent') }>Excellent</button>
</Link>
<Link to="/wEight">
<button onClick={ () => updateCredit('Good') }>Good</button>
</Link>
<Link to="/wEight">
<button onClick={ () => updateCredit('Fair') }>Fair</button>
</Link>
<Link to="/wEight">
<button onClick={ () => updateCredit('Poor') }>Poor</button>
</Link>
</div>
</div>
</div>
)
}
}
function mapStateToProps( state ) {
const { credit } = state;
return {
credit
};
}
export default connect( mapStateToProps, { updateCredit } )( WizardSeven );
src/components/WizardEight/WizardEight.js
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import { connect } from 'react-redux';
import { updateHistory } from '../../ducks/reducer';
class WizardEight extends Component {
render() {
const { updateHistory } = this.props;
return (
<div className="parent-div">
<div className="vert-align">
<p>Have you had a bankruptcy or foreclosure in the past seven years? </p><br />
<div className="row">
<Link to="/wNine">
<button value="Has never been in bankruptcy" onClick={ ( e ) => updateHistory( e.target.value ) }>No</button>
</Link>
<Link to="/wNine">
<button value="Has had bankruptcy before" onClick={ ( e ) => updateHistory( e.target.value ) }>Bankruptcy</button>
</Link>
<Link to="/wNine">
<button value="Has had a foreclosure before" onClick={ ( e ) => updateHistory( e.target.value ) }>Foreclosure</button>
</Link>
<Link to="/wNine">
<button value="Has had both a foreclosure and a bankruptcy" onClick={ ( e ) => updateHistory( e.target.value ) }>Both</button>
</Link>
</div>
</div>
</div>
)
}
}
function mapStateToProps( state ) {
const { history } = state;
return {
history
};
}
export default connect( mapStateToProps, { updateHistory } )( WizardEight );
src/components/WizardNine/WizardNine.js
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import { connect } from 'react-redux';
import { updateAddress1, updateAddress2, updateAddress3 } from '../../ducks/reducer';
class WizardNine extends Component {
render() {
const { updateAddress1, updateAddress2, updateAddress3 } = this.props;
return (
<div className="parent-div">
<div className="vert-align">
<p>What is your address?</p> <br />
<input type="text" placeholder="Line One" onChange={ ( e ) => updateAddress1( e.target.value ) } />
<input type="text" placeholder="Line Two" onChange={ ( e ) => updateAddress2( e.target.value ) } />
<input type="text" placeholder="Line Three" onChange={ ( e ) => updateAddress3( e.target.value ) } />
<Link to="/wTen">
<button className="margin-btn"> Next </button>
</Link>
</div>
</div>
)
}
}
function mapStateToProps( state ) {
const { addressOne, addressTwo, addressThree } = state;
return {
addressOne,
addressTwo,
addressThree
};
}
export default connect( mapStateToProps, { updateAddress1, updateAddress2, updateAddress3 } )( WizardNine );
src/components/WizardTen/WizardTen.js
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import { connect } from 'react-redux';
import { updateFirst, updateLast, updateEmail } from '../../ducks/reducer';
class WizardTen extends Component {
render() {
const { updateFirst, updateLast, updateEmail } = this.props;
return (
<div className="parent-div">
<div className="vert-align">
<p>What is your name?</p> <br />
<input type="text" placeholder="First Name" onChange={ ( e ) => updateFirst( e.target.value ) } />
<input type="text" placeholder="Last Name" onChange={ ( e ) => updateLast( e.target.value ) } />
<input type="text" placeholder="email" onChange={ ( e ) => updateEmail( e.target.value ) } />
<Link to="/wEleven">
<button className="margin-btn"> Next </button>
</Link>
</div>
</div>
)
}
}
function mapStateToProps( state ) {
const { firstName, lastName, email } = state;
return {
firstName,
lastName,
email
};
}
export default connect( mapStateToProps, { updateFirst, updateLast, updateEmail } )( WizardTen );
Contributions
If you see a problem or a typo, please fork, make the necessary changes, and create a pull request so we can review your changes and merge them into the master repo and branch.
Copyright
© RomanFSDev LLC, 2017. Unauthorized use and/or duplication of this material without express and written permission from RomanFSDev, LLC is strictly prohibited. Excerpts and links may be used, provided that full and clear credit is given to RomanFSDev with appropriate and specific direction to the original content