React Redux Project — Flatiron School
By: Barbara Johnson
Tags: Redux, Flatiron School, JavaScript, React

For my final portfolio project, I created an app called I Had That! to allow users to keep a collection of childhood toys they had. Seeing retro toys takes you back in time and you start reminiscing about the fun times playing with your toys. In the early 80s, I had a Commodore VIC-20 (not as cool as the higher-end Commodore 64) which taught me the BASIC programming language. It connected to our TV and if I turned the channel to 3, the TV became the monitor!

The app allows users to sign up, log in, and start adding toys to their library. If the toys is not listed in the library, the user can add a new toy.

1. Rails API

The first step in creating this app is to set up the Rails backend.

Models and Associations

The backend implements a User model, a Toy model, and a joint table between the user and toy called ToyOwnership.

User

has_many :toy_ownerships, dependent: :destroy has_many :toys, through: :toy_ownerships

2. Toy

has_many :toy_ownerships, dependent: :destroy has_many :users, through: :toy_ownerships

3. ToyOwnership

belongs_to :user belongs_to :toy

CORS

Cross-origin resource sharing (CORS) is a mechanism that allows restricted resources on a web page to be requested from another domain outside the server’s domain.

For this project, the config/initializers/cors.rb is configured to allow requests from http://localhost:3001 and to allow [:get, :post, :patch, :delete] requests to the API.

Rails.application.config.middleware.insert_before 0, Rack::Cors do

allow do

origins 'http://localhost:3001'

resource '*',

headers: :any,

methods: [:get, :post, :put, :patch, :delete, :options, :head],

credentials: true end

end

Serializer

The Active Model Serializer is used to build the JSON objects. It allows me to select only the information I want to display.

Toy Serializer

2. React App

To get up to speed with React quickly, I used the create-react-app generator to start my project. It provides a React application starter to build a single-page React app.

3. React-Redux

React-Redux allows your React components to read data from a Redux store, and dispatch actions to the store to update data.

The <Provider /> makes the Redux store available to the rest of the app.

import React from 'react';

import ReactDOM from 'react-dom';

import './index.css';

import App from './App';

import { Provider } from 'react-redux';

import store from './store' ReactDOM.render(

<Provider store={ store }>

<App />

</Provider>, document.getElementById('root'));

React Redux also provides a connect function which allows you to connect your component to the store.

The mapStateToProps is used for selecting the part of the data from the store that the connected component needs. It returns a plain object that contains the data the component needs. In this case, it returns the user and toys objects.

import React, { Component } from 'react';

import { connect } from 'react-redux';

import ToyCard from '../components/ToyCard';

import { Card, Divider } from 'semantic-ui-react'; class MyStuff extends Component {

...

} const mapStateToProps = (state) => {

return ({

user: state.currentUser,

toys: state.toys

})

} export default connect(mapStateToProps)(MyStuff);

4. Redux-Thunk Middleware

Redux-Thunk is a middleware used to handle asynchronous actions in Redux. By default, Redux action creators do not support asynchronous actions like fetching data, so we need to utilize Redux Thunk. Using this middleware avoids running into a problem where the action creator returns an action before the data is fetched.

// Asynchronous action creators

export const login = credentials => {

return dispatch => {

return fetch("http://localhost:3000/api/v1/login",

{ credentials: "include",

method: "POST",

headers: { "Content-Type": "application/json" },

body: JSON.stringify(credentials)

})



.then(r => r.json())

.then(user => {

if (user.error) {

alert(user.error)

} else {

dispatch(setCurrentUser(user))

dispatch(getMyToys(user))

}

})

}

}

5. Router

React Router allows single page applications (SPA) to navigate through multiple views without having to reload the entire page.

In the Route component, we pass the two props: the path and the component the user sees when they navigate to the path.

import { BrowserRouter as Router, Route, Switch} from 'react-router-dom'; ... class App extends React.Component { ... render() { let loggedIn=this.props.currentUser.username return ( <div> <Router>

<div className="App">

<NavBar /> <h3>I HAD THAT!</h3> { loggedIn ? <Logout /> : <div> <Login /> <Signup /> </div> }

{ loggedIn ? <ToyForm /> : ""} <Switch>

<Route exact path="/" component={Home}/>

<Route path="/toys" component={Toys} />

<Route path="/myStuff" component={MyStuff} />

<Route path="/about" component={About}/>

</Switch> <Divider />

<Footer />

</div> </Router> </div> );

}

}

Here’s a screenshot of the user’s list of claimed toys which are selected from the View All Toys page. View the source code here.