DEV Community

Cover image for Project 70 of 100 - Rick Redux
James Hubert
James Hubert

Posted on

Project 70 of 100 - Rick Redux

Hey! I'm on a mission to make 100 React.js projects ending May 31st. Please follow my dev.to profile or my twitter for updates and feel free to reach out if you have questions. Thanks for your support!

Link to today's deployed app: Link
Link to the repo: github

Background

Today was another day of interacting with Redux at the most basic level. For those curious about my process or how I come up with these nearly useless project ideas, I do an hour a day of online programming coursework and follow it with an hour where I'm free to build whatever I can think of to practice the day's concepts.

Right now I'm in the final segment of Bob Ziroll's React Bootcamp on Scrimba, which I highly recommend if you're interested in learning React. I also highly recommend Scrimba for anyone learning web development.

Anyway, on to the project. Today I built a web application from Create React App that embedded a Youtube video of the famous Rick Roll music video. The goal was to build a little application that interacted with a totally basic vanilla Javascript implementation of Redux for storing state. The actual Redux functionality was almost identical to yesterday's project except that it includes functionality for changing the title of the video, which changes the way the reducer looks.

Setting up Redux

Here I'll walk you through what that Redux file looks like:

  1. First, we have to import Redux (after installing it with npm i redux) and include it in the file.
// require redux
const redux = require('redux')
Enter fullscreen mode Exit fullscreen mode
  1. Second, we need to set up our actions. These tell our reducer (more on that later) what to do when it interacts with state. Notice this formally creates and at the same time restricts the ways in which we can interact with the application's state.
// define actions
function upVote() {
  return {
    type: "UPVOTE"
  }
}

function downVote() {
  return {
    type: "DOWNVOTE"
  }
}

function rename(name) {
  return {
    type: "RENAME",
    payload: name
  }
}
Enter fullscreen mode Exit fullscreen mode
  1. Next, we create a state object just to put some initial values. This isn't a required part of using Redux, but it makes our lives easier in this particular application.
// create state object
const initialState = {
  votes: 0,
  name: "Never Gonna Give You Up"
}
Enter fullscreen mode Exit fullscreen mode
  1. After defining our actions, it's time to create the reducer. This is the function that receives as an argument a previously-defined action, which typically has a payload, or data, that all together tell the reducer exactly how it should retrieve data from state to deliver that data in a meaningful way to components using the data.
// create reducer
function reducer(state = initialState, action) {
  switch(action.type) {
    case ("UPVOTE"):
      return {
        ...state,
        votes: state.votes + 1
      }
    case ("DOWNVOTE"):
      return {
        ...state,
        votes: state.votes - 1
      }
    case ("RENAME"):
      return {
        ...state,
        name: action.payload
      }
    default:
      return state
  }
}
Enter fullscreen mode Exit fullscreen mode
  1. After our actions and reducer are set up, we can create a store, which uses the built-in createStore() method from the redux package. This, as the method says, creates a special store that has a lot of built in functionality that comes with the redux package. It's kind of like a really buffed-up version of the native React state.
// create store from reducer
const store = redux.createStore(reducer)
Enter fullscreen mode Exit fullscreen mode
  1. Then, we need to subscribe to changes in the store. This is one of those pre-built redux methods I mentioned earlier that is available on redux stores. This method provides a callback that you can use to interact with the data in the store, as it is changed.
// subscribe to store changes and console.log() them
store.subscribe(() => {
  console.log(store.getState())
})

7. You are now free to use your actions. I am exporting them for use in other files.

Enter fullscreen mode Exit fullscreen mode


JS
// export
export {upVote,downVote,rename,store};


##Interacting with our Reducer, and the Store
The next part of this project is to build out functionality in our React components that allows the user to interact with state. I *know for a fact* that I am not using Redux in the React way. I'm pretty sure there's even a special library for using Redux in React that I'm not using here. But remember what I said about using tech from my courses in that day's projects? Yeah, so we'll hopefully get to the React uses tomorrow.

OK- with warnings out of the way, here was my solution for interacting with Redux in other components. In my Control component, which is a JSX component that appears below the embedded Youtube video and has the buttons and votes readout, I have upvote and downvote buttons. In order for these buttons to interact with the store from our Redux file and actually use the actions we built to get data from the reducer, we have to bring in the store and our `upVote` and `downVote` functions: 

Enter fullscreen mode Exit fullscreen mode


JS
import React,{useState,useEffect} from 'react'
import {store,upVote,downVote} from '../redux'

function Contol() {
const [videoState,setVideoState] = useState({})

useEffect(() => {
setVideoState(setVideoState(store.getState()))
}, [])

store.subscribe(() => {
setVideoState(store.getState())
})

const handleUpVote = () => {
store.dispatch(upVote())
}

const handleDownVote = () => {
store.dispatch(downVote())
}

return(...)
...


As you can see I handle up and down votes with their own handler functions which call `store.dispatch()` to dispatch the actions and trigger a change in the store, which the subscriber has access to, and when changes are detected there I save those changes in a local state variable for use in this component. 

Here is how the component uses it, in the JSX:

Enter fullscreen mode Exit fullscreen mode


JS
return (



Votes: {videoState ? videoState.votes : 0}




Vote Down 👎
Vote Up 👍


)

Above you can see that we are using the votes from state, and the two actions we imported from our redux file.

Next, I built the edit functionality into the `TitleEdit` component. For that, I only imported the store and my rename action. I also used an isEditing boolean flag to display either an input or the title in plain text. If the user clicks 'Save' after editing, we trigger the rename action in the `handleRename()` function.

Enter fullscreen mode Exit fullscreen mode


JS
import React,{useState} from 'react'
import {store,rename} from '../redux'

function TitleEdit() {
const [isEditing,setIsEditing] = useState(false)
const [currentName,setCurrentName] = useState("Never Gonna Give You Up")

store.subscribe(() => {
const storeObject = store.getState()
setCurrentName(storeObject.name)
})

const handleRename = () => {
store.dispatch(rename(currentName))
}

function handleEditClick() {
isEditing && (
// was editing, now save and go back to normal
handleRename()
)
setIsEditing(prevState => !prevState)
}
return(...)
...


Now here is the JSX:

Enter fullscreen mode Exit fullscreen mode


JS
return (



{isEditing ?

type="text"
placeholder="Enter new title"
value={currentName}
className="form-control"
onChange={e => setCurrentName(e.currentTarget.value)}
>
:
{currentName}{' '}
}
onClick={handleEditClick}
className="btn btn-light btn-sm"
>
{isEditing ? "Save" : "Edit"}



)



And that is my fully interactive custom made Redux state. If you're interested in this subject, I highly recommend you read more about it [here](https://www.youtube.com/watch?v=oHg5SJYRHA0), where it is handled in more detail.

**If you like projects like this and want to stay up to date with more, check out my Twitter [@jwhubert91](https://twitter.com/jwhubert91), I follow back! See you tomorrow for another project.**
Enter fullscreen mode Exit fullscreen mode

Top comments (0)