Please read Part 1 and Part 2 here
In the previous post, we discussed the React Components to display the jobs list. The JobsList component calls the this.props.loadJobs() method when mounted. The Redux magic is woven inside in this method.
The following things happen during the invocation of loadJobs() method
- Fetch the job postings from the server
- Pass the job postings JSON to the jobsReducer
- The jobsReducer modifies the state with the job postings
The loadJobs() method is shown below.
const mapDispatchToProps = dispatch => {
const request = axios.get('/load/jobs')
request.then(response => {
let payload = response.data
dispatch({
type: "LOAD_JOBS_SUCCESS", payload
})
})
request.catch(error => {
dispatch({
type: "LOAD_JOBS_ERROR", error: error
})
})
return {
loadJobs: () => request
}
}
Ahem!!! What's going on in the above code? There are lot more things that happen over here. You'll notice that we send an AJAX request to /load/jobs. Once you receive the response, based on the outcome, we dispatch the data to the store using the dispatch() method. And who provides the dispatch handle? We'll see that in a minute.
Why do we need to pass the jobs to the reducers? Why can't we handle them in this method itself? Let's recollect Redux fundamentals. The data flow is uni-directional. So we always pass the payload to the store, which dispatches the action and data to the reducers and the reducers return a modified state. So it's view->store->reducers
The jobsReducers does the following when it receives the LOAD_JOBS_SUCCESS and LOAD_JOBS_ERROR actions.
//...
case "LOAD_JOBS_SUCCESS":
state.jobs = action.payload.jobs
return {jobs: action.payload.jobs, addJobShown: false}
case "LOAD_JOBS_ERROR":
return {jobs:state.jobs ,addJobShown: false}
//...
Let's get back to the JobsList component. We will create a list of properties used by the component. The properties are simple extractors, that extract data from the state as shown below.
const mapStateToProps = (state) => {
return {
jobs: state.jobs,
addJobShown: state.addJobShown
}
}
As you can notice, the mapStateToProps and mapDispatchToProps need to be finally connected with the store and the JobsList component. And this one line, does that.
export default connect(mapStateToProps,mapDispatchToProps)(JobsList);
The connect() method present in react-redux module wires the component and store together. Given below, is the skeleton of the JobsList component.
import {connect} from 'react-redux'
class JobsList extends Component{
//...
}
const mapStateToProps = (state) => {
//...
}
const mapDispatchToProps = dispatch => {
//...
}
export default connect(mapStateToProps,mapDispatchToProps)(JobsList);
In a similar fashion, we can develop the create job posting and delete job posting components. In a nutshell, you may want to remember the following while developing a React Component with Redux.
- Define the list of properties to be used by the component
- Define the list of methods that will dispatch a call to the reducers
- The event handlers of the UI components will call the dispatch methods
- Connect the dispatch methods and properties with the component
Production mode
Our Express JS server runs on 3001 and the React development server on 3000. Let's bring them together in production.
You can build your React application using npm run build and copy the contents of the build folder into Express application folder. You can create a folder say client in Express JS application and dump your build contents in it. Let's connect these two now. The initial request to the application should be routed to client/index.html as shown here
app.use(express.static(path.join(__dirname, 'client')));
And that's it!!! We are all set. :) The application runs in http://localhost:3001
The complete code for the application can be found in this GitHub repository. https://github.com/prabhu-durasoft/react-redux-express-example