17
loading...
This website collects cookies to deliver better user experience
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
import { useEffect } from 'react';
import { fetchProjects } from './projectAction';
import { useSelector, useDispatch } from 'react-redux'
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.
fetchProjects
is a functional component I created just to handle get request.
useDispatch
is similar to connect
. useDispatch
is React Hooks' way to trigger a state change.
useSelector
is similar to how we would call "this.props.projects" to get data from the redux store; now we have useSelector
.
export default function ProjectDisplay() {
const projects = useSelector(state => state.projects)
const dispatch = useDispatch()
useEffect(() => {
dispatch(fetchProjects())
}, [])
}
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))
const
declaration of "dispatch" gives us access to the usDispatch function by just calling DispatchuseEffect
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, 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})})
}
}
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.
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.
state
inside of our store, we must modify the information in our reducers. After the fetch request, the second dispatch accesses the reducer. export default function projectReducer(state=[], action) {
switch(action.type){
case "SET_PROJECTS":
return action.payload;
}
}
dispatch({type:SET_PROJECTS, payload: projects}
).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 .const projects = useSelector(state => state.projects)
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>
)