---
# System prepended metadata

title: 'Week 4 Notes: Redux, React Router, Forms'

---

# Week 4 Notes: Redux, React Router, Forms

## Redux

### **Start Here: [State Scenarios and Why Redux](https://drive.google.com/file/d/1HQMHTMmcFN-2Jv2WlFU5Ioyc18EP_pmd/view?usp=sharing)**

Below are images of the above resource

### [Prop Drilling](https://kentcdodds.com/blog/prop-drilling)

![](https://i.imgur.com/qxEKrPT.png)

### [Lifting State Up](https://reactjs.org/docs/lifting-state-up.html)

![](https://i.imgur.com/wP57lfK.png)


### What Happens When Our Application (and State) Get Large

![](https://i.imgur.com/1CFzfik.png)


### React's Job and Redux's Job

React can do its own state management, but we are letting Redux do that. React's job will be DOM Manipulation and Presentation of Data. See [thunk](https://hackmd.io/8QGBGT03TKWlj7RvG5DJWw#Thunks) section to see that we are taking async calls away from React as well, and putting it into Redux via thunks. 

![](https://i.imgur.com/XYfvsgR.png)


The point of Redux is to keep our state in a centralized place for our components to grab as necessary. If our Redux state has Pokémon, Digimon, and Marvel Characters, and a React component is supposed to deal with Pokémon, then we just use that piece of state. 

### [Creating our Own Redux Store](https://www.youtube.com/watch?v=yOo4Nemntpc)

```javascript=
/*
    Create our own Redux store!!!
*/

// Create an initial state for us to use
const initialState = {
    balance: 0
}

// Create a store function that takes in a reducer as an argument
const createStore = (reducer) => {
    // Declare an "internal state" variable
    let state
    // Keep track of our "subscriptions" or listeners
    // Keeping track of the "store.subscribe"
    let listeners = []

    /*
        getState Function => which returns the current state
    */
    const getState = () => state

    /*
        dispatch function
        The goal of dispatch is that it will call the reducer with:
        1. The current state
        2. The action (object) that has been passed to it
        Remember: We passed in the reducer so it will check for our cases
    */
    const dispatch = (action) => {
        /*
            Call our reducer with the current state and action
            The return value from our reducer (whether it's the default case or one of our defined cases)
            **Will be the new state and we will set it to our store's internal state**
        */
       state = reducer(state, action)
       console.log('Inside dispatch: ', state)
       /*
            Important: When we can subscribe with a callback function, we are setting a subscription to our store
            and when dispatch is called, the below is called where we traverse through our listeners array and we will run
            the functions that are in it
       */
        listeners.forEach(l => l())
    }

    /*
        Subscribe function => This sets up our subscriptions as well as providing a returned function that unsubscribes
    */
    const subscribe = (listener) => {
        // We pass in a listener (the callback function) and push it into the listeners array
        listeners.push(listener)
        console.log('I am the listeners array: ', listeners)
        // Return a function that:
        return () => {
            // Filters through the listeners and removes the listener that was passed in
            listeners = listeners.filter(lis => lis !== listener)
            console.log('I am the listeners array after the unsubscribe has been called: ', listeners)
        }
        
    }
    /*
        Call the first dispatch to get the first state
        If we don't have this, our initialState when we run store.getState() will be undefined
    */
   dispatch({})
   /*
        Return the functions from our mock store
   */
  return { getState, dispatch, subscribe }
}



// Create a reducer
const reducer = (state = initialState, action) => {
    switch(action.type) {
        case 'DEPOSIT':
            return {
                balance: state.balance + action.amount
            }
        default:
        return state
    }
}

// Create store and pass it in our reducer
const store = createStore(reducer)
console.log('This is the store: ', store)
// Get our initial state
console.log('Hey this is initial state: ', store.getState())
/* subscribe to changes in state when we call dispatch
    But ALSO set it some variable so we can store the return value (the anonymous function) in it
    So we can call it later
*/
let someValue = store.subscribe(() => console.log('Updated State: ', store.getState()))
// Trigger state changes
store.dispatch({type: 'DEPOSIT', amount: 10})
store.dispatch({type: 'DEPOSIT', amount: 10})

// Actually call the function returned from subscribe and note that the listeners array is empty
console.log(someValue())
```


### React-Redux

#### `mapStateToProps`

Take the piece of the state(s) from Redux we need for this component and put them on the props object

```javascript=
const mapStateToProps = (state) => {
  console.log('Mapping state to props: ', state)
  return {
    // The key is the name that will be attached to our props object
    countAttachedToProps: state.count // This is coming from Redux
  }
}
```


#### `mapDispatchToProps`

Take the action creators/thunk creators (mostly thunk creators) from Redux we need for this component to use and put them on the props object

```javascript=
const mapDispatchToProps = (dispatch) => {
  console.log('Mapping dispatch to props: ', dispatch)
  // The key is the name that will be attached to the props object
  return {
    incrementAttachedToProps: () => dispatch(increment())
  }
}
```

#### `connect`

Without `connect` we'd have to manually subscribe and unsubscribe to the Redux store via `componentDidUpdate` and `componentWillUnmount` in the React lifecycle methods. 

We use the component's `props` object to map what we need from Redux into it. 

```javascript=
// We have to "connect" the component
// Two arguments that we currently need (mapStateToProps, mapDispatchToProps)
// Immediately invoke it (connect) to our Counter component
// Create a NEW component called ConnectedCounter. This does NOT modify the original component
const ConnectedCounter = connect(mapStateToProps, mapDispatchToProps)(Counter)
```

#### `Provider`

```javascript=
// Provider attaches the Redux store to something called "React's context"
ReactDOM.render(
  <Provider store={store}>
    <ConnectedCounter />
  </Provider>,
  document.getElementById('app')
)
```

### Thunks

- [Joe's Thunk Gist](https://hackmd.io/8QGBGT03TKWlj7RvG5DJWw#Thunks)

The point: To take asynchronous requests away from React and contain them in Redux. The asynchronous call is a function that requests information from our server (via axios) to eventually be returned as an object (JSON). We need thunk middleware to be the bouncer so that we don't send a function to the reducer but instead we dispatch the data that we eventually get from the server


```javascript=
// THUNK CREATOR or ASYNC ACTION CREATOR

export const fetchPokemon = () => {
    // thunk
    return async (dispatch) => {
        console.log('----------Called from thunk in Redux-----------')
        try {
            // axios request to API
            const { data } = await axios.get('/pokemon')
            // dispatch to our action creator to change state
            dispatch(gotPokemon(data))
        }
        catch (error) { console.log(error) }
        

    }
}
```


### `combineReducers`

The point: If our state has so many resources: Food, Drinks, Books, Users, etc, then our Reducer would get monstrous. So, we use `combineReducers` to give us the functionality of creating separate subreducer files for different resources. This is similar to Express Router

## React Router

### What is the purpose of the react-router-dom library?

The react-router-dom library is the routing library used for React web applications. It keeps the UI in sync with the URL, meaning that it uses the URL in the browser to determine what kind of presentation a visitor should receive without reloading the browser.

### What are the main components we import from react-router-dom?

* Router - HashRouter (adds a # after the root URL and preferable to use when you don’t have a server or server only responds to static files) or BrowserRouter (does not add a # and preferable to use when you have a server that will be able to handle any possible URL); the Router component should be the parent component of an application because when the URL changes, the Router component’s state will update, which initiates a render; therefore, when the route changes, all parts of an application should be given a change to update

* Route = Path + Component
`<Route path=‘/somePath’ component={SomeComponent} />` : if the path starts with `/somePath`, then the `SomeComponent` will render; if we want an exact matching of the path, then we add the `exact` prop to the `Route` component

* Link
`<Link to=‘/somePath’>Link to SomePath</Link>` : coupled with the Route example above, when a user clicks on the Link to SomePath, the URL bar will change to /somePath, which will then cause the `SomeComponent` to render

### What props are passed down by the Route component to the rendered component?

* `match` - contains information about how the route’s path matches the current URL; most notably, it includes a params key that parses the URL parameters

* `history` - used to manipulate the browser’s history programmatically using properties on the history object, such as history.push; the history prop can be used when you don’t want to use a Link and instead want to perform some sort of JavaScript before router user to another page

* `location` - contains information about where the url is now


### How do we pass additional props to the component being rendered by the Route component?

```
<Route path='/puppies' component={Puppies} />

vs.

<Route path='/puppies' render={(routeProps) => <Puppies {...routeProps} />} />
```
* the  `routeProps` in the above example are match, history, and location; if we do not need those props in the rendered component, we can omit them

## React Forms

### What is the difference between a controlled and an uncontrolled form component?

A controlled component has a value prop which is directly set (controlled) by application state. Changes to the value on state will update what you see on the form.

Uncontrolled components do not have a value prop tied to application state. Updates to state will NOT be reflected in the form component.

### What is the difference between application state and local state?

Application state is data that may be needed by multiple parts of your application. For instance, the logged-in user. This data should be managed high up on the state tree, where it can be passed down to wherever it may be needed.

Local state is data that is only needed by a particular component, such as ephemeral data input into a form. The rest of the application usually doesn't need to know what the user is typing into a form until the form is submitted. This state does not need to be shared with other components, and can therefore be isolated to just the form component

### Getting Data From Forms

#### Submit Event

This doesn't keep form data on state and we are unable to do inline form validation. Example of when this is used: Submitting comments on social media; writing large blog posts

#### Change Event

This places the data on state and we are able to calculate validations on each change (likely each keystroke). Example of when this is used: Credit Card Validation, Password Validation

#### Example Form

```javascript=
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { addNewUser } from '../store/users'

const initState = {
    name: '',
    favoriteFood: ''
}

class Form extends Component {
    constructor(props) {
        super(props)
        this.state = initState
        this.handleChange = this.handleChange.bind(this)
        this.handleSubmit = this.handleSubmit.bind(this)
    }

    handleChange(event) {
        // console.log(event)
        console.log('[event.target.name]: ', event.target.name)
        console.log('This is its value: ', event.target.value)
        /*
            We are using handleChange for ALL inputs.
            So, we want to make sure that our state reflects what we've input into the form
            The bracket notation is to be able dynamically update an object's properties
            When we DON'T know what that property is going to be beforehand
            
            Just use the same onChange handler
        */
        this.setState({
            [event.target.name]: event.target.value
        })
    }

    handleSubmit(event) {
        // Please, prevent the default behavior of HTML from happening
        event.preventDefault()
        // console.log('Running inside handleSubmit', event)
        // The next step is to add the new user to the database
        // Dispatch the user to our addNewUser thunk
        // Pass into it our state
        this.props.addUser(this.state)
        // When we submit, we should clear the state so that form can be re-used
        this.setState(initState)
    }

    render() {
        return(
            <div>
                <span>Fill out form to add a user and their favorite food</span>
                <form onSubmit={this.handleSubmit}>
                    <div className='container-form-field'>
                        <label htmlFor='name'>Name</label>
                        <input
                            type='text'
                            name='name'
                            value={this.state.name}
                            onChange={this.handleChange}
                        >
                        </input>
                    </div>

                    <div className='container-form-field'>
                        <label htmlFor='favoriteFood'>Favorite Food</label>
                        <input
                            type='text'
                            name='favoriteFood'
                            value={this.state.favoriteFood}
                            onChange={this.handleChange}
                        >
                        </input>
                    </div>
                    <button type='submit'>Submit!</button>
                </form>
            </div>
        )
    }
}

const mapDispatchToProps = (dispatch) => {
    return {
        addUser: (user) => dispatch(addNewUser(user))
    }
}

export default connect(null, mapDispatchToProps)(Form)
```

### [`componentDidUpdate`](https://www.youtube.com/watch?v=lTuABymmVX4)