React Hooks and Fetch

This blog will be detailing how to use React Hooks with Fetch to get data.

"Note that all React packages need to be 16.8.0 or higher to enable Hooks. Hooks won't work if you forget to update".

Backend

Let's first look at the database I used for this demonstration. I used a rails API, but we won't be getting any deeper than this; all you need to know are the attributes that are set up in the table to understand the examples.

create_table "projects", force: :cascade do |t|
    t.string "title"
    t.string "description"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
  end

This code snippet shows a table called "Projects" that has 2 attributes "Title" and "Description".

Frontend

Project Display Component

Displayed is the "project display functional component". The goal. heere. is to have this component fetch all the projects from my backend so that it can be displayed.

Let's first take a look at the "imports"

import { useEffect } from 'react';
import { fetchProjects } from './projectAction';
import { useSelector, useDispatch } from 'react-redux'
  1. useEfect is similar to componentDidMount() which runs additional code before React has updated the DOM. This is important because we want to get our data before the page loads. No data means no projects can be displayed on the DOM. How do we get our data? Yes, Fetch!
    This is where the fetch request is happening.

  2. fetchProjects is a functional component I created just to handle get request.

  3. useDispatch is similar to connect. useDispatch is React Hooks' way to trigger a state change.

  4. useSelector is similar to how we would call "this.props.projects" to get data from the redux store; now we have useSelector.

Putting It All Together

Project Display Component Functions and Declarations
export default function ProjectDisplay() {

  const projects = useSelector(state => state.projects)
  const dispatch = useDispatch()

  useEffect(() => {
    dispatch(fetchProjects())
  }, [])
}
  1. const declaration of "projects" is the return value of useSelector. How you set up your reducer(s) and store reflects how you call your state. Typically if you only passed in 1 reducer component in my redux store, you would just use const projects =useSelector(state => state), but I passed in a combineReducer, which like it says, combines all the different reducer components, so you have to specify which one you want. How the Store looks like ...
import { applyMiddleware, createStore, combineReducers } from "redux";

import thunk from "redux-thunk"
import userReducer from "./reducers/userReducer";
import projecReducer from "./reducers/projectReducer"
import taskReducer from "./reducers/taskReducer"


let rootReducer = combineReducers({user: userReducer, projects: projecReducer, tasks:taskReducer  })

export default createStore(rootReducer, applyMiddleware(thunk))

2.const declaration of "dispatch" gives us access to the usDispatch function by just calling Dispatch

  1. useEffect takes in 2 arguments. The first argument takes in a function. In this example, we created a call-back function with dispatch to trigger a change instate. Then in our function dispatch we call on our fetch function (fetchProject). The second argument in useEffect takes in an array of dependencies. In this example, we have none, so we left the array empty.
Fetch Function (fetchProject)

You should already be familiar with how to write a fetch function, so I will only be getting into how it changes our state.

export function fetchProjects(){
    return dispatch => {
        fetch('http://localhost:3000/projects')
        .then(r => r.json())
        .then( projects => { 

            dispatch({type:"SET_PROJECTS", payload: projects})})
    }
}
  1. What is fetch doing? Fetch is going to the url provided, in this case the route of my backend and 'GET'/getting all the projects.

  2. The new addition to this fetch request is dispatch({type:SET_PROJECTS, payload: projects}. In the second promise of our function. We call dispatch to change the state, which we still need to do within the fetch request. dispatch takes in an action, an object that describes what happened ({type:SET_PROJECTS, payload: projects}). type is a string used to match our case in the switch statement (located in the reducer which changes our store's state). payload in this example is the data retrieved.

Change state with Reducers

Remember that we are passing in reducers to our redux store, so to change our state inside of our store, we must modify the information in our reducers. After the fetch request, the second dispatch accesses the reducer.

This is the Project Reducer:

export default function projectReducer(state=[], action) {
    switch(action.type){
        case "SET_PROJECTS":

            return action.payload; 
    }
}
  1. The project reducer takes in 2 arguments. 1. the state, which is being defaulted to an empty array, and 2. action, which is what refers to the object that was sent through dispatch (dispatch({type:SET_PROJECTS, payload: projects}).

2.With switch the value of the expression (action.type) is compared with the values of each case. in this example, we used action.type, which renders out to be "SET_PROJECTS" because it is what was passed through in our dispatch. In the case statement, we are returning the state. By calling action.payload the state is snow equal to the data we got from our fetch, which is an array of Project objects .

Back to Project Display Component to render
const projects = useSelector(state => state.projects)

Now that our state is an array of project objects We can render them in our DOM. remember our useSelector function declared earlier in the project component? We can use the const project like this ...

return(
 <div>
            <h1>Projects</h1>
            <ul>

                {projects.map(p =>{
                return(
                    <li key={p.id}>


                        <p>{p.description}</p>
                        <p>{p. completion_rate}</p>
                        <button onClick={()=>{handleClick({p})}}>Delete</button>

                    </li>
                )})}
            </ul>
        </div>             
)

As you can see we are mapping through projects and displaying each project in an unordered list on the DOM.

15