DEV Community

Cover image for React(.js)ing to My New Foster Kittens: A React/Redux Application
Taylor Sieling
Taylor Sieling

Posted on

React(.js)ing to My New Foster Kittens: A React/Redux Application

The Project

All of my Flatiron School projects have related to my interests and passions, and my React.js project is probably closest to my heart. I have recently started fostering kittens through my local Humane Society, and as such built an application to manage kitten intakes and updates. Users can input all pertinent intake information when getting new fosters, and edit/delete the information as necessary.

The Structure

Routes

/
/kittens
/kittens/:id
/kittens/:id/edit
/kittens/intake

Presentational Components

Home.js
Navigation.js
Footer.js
KittenCard.js - for the Kitten Index page
KittenShow.js - for the Kitten Show page

Container Components

Kittens.js - for the Kitten Index page
KittenContainer.js - for the Kitten Show page
IntakeForm.js - new Kitten form
EditForm.js - edit Kitten form

The Rails API Backend

I set up my Model and Controller using the Rails resource generator. I created my seeds, enabled CORS, and set-up my JSON serializer.

The React.js Frontend

I used create-react-app to get started with my frontend. I set-up my folders for Containers, Components, Actions, and Reducers.

Using Redux

Although React Hooks are replacing Redux, I appreciated getting to learn the Redux pattern. Redux lets you create a store to hold your state. The store can dispatch an action to the appropriate reducer and create an object to make changes to the state. Components are then able to re-render on the DOM with the new data.

I used my Redux store to hold information about my kittens, which could be passed to my Presentational Components. My Presentational Components are stateless and accept props mapped from their Container Component's state. I used Functional Components within my Presentation Components.

My Container Components, which needed access to my Redux store and certain Lifecycle Methods, were build using Class Components.

Redux-Thunk Middleware

Javascript web requests are asynchronous, meaning our fetch requests can run into an issue where our action creator returns an action before the API data is actually fetched.

The Thunk middleware allows us to return a function inside of the action creator, rather than a Javascript object. That function can dispatch multiple actions, depending on whether the loading state is true or false.

Here is an example of the Redux-Thunk middleware in action:

// src/containers/KittenContainer.js

class KittenContainer extends Component {

    componentDidMount() {
        this.props.fetchKittens();
    }

    ...

}
Enter fullscreen mode Exit fullscreen mode

I call my fetchKittens() method in my componentDidMount() lifecycle method.

// src/actions/kittens.js

export const fetchKittens = () => {

    return (dispatch) => {
        dispatch({ type: "LOADING_KITTENS"})
        fetch('http://localhost:3001/kittens')
        .then(res => res.json())
        .then(kittens => {
            console.log('fetching kittens')
            dispatch({
            type: "KITTENS_LOADED", 
            payload: kittens
        })
        })
    }

}

Enter fullscreen mode Exit fullscreen mode

I pass the dispatch method (from the store) into my returned function, and call dispatch twice in the function's body. The first dispatch indicates that I am loading the kitten data from my API. The second dispatch makes the actual GET request to the server.

// src/reducers/kittenReducer.js

const kittens = (state = { kittens: [], loading: false}, action) => {
    switch(action.type){
        case "LOADING_KITTENS":
            return {
                ...state,
                loading: true
            }
        case "KITTENS_LOADED":
            return {
                ...state, 
                kittens: action.payload,
                loading: false
            }

    ...

Enter fullscreen mode Exit fullscreen mode

Here you can see my case switches in my kittenReducer.js.

// src/containers/KittenContainer.js 

    handleLoading = () => {
        if (this.props.loading) {
            return (
                <div>
                    <div className="kittens">
                        <div className="home-text">
                            <h1>Knittin' Kitten Foster</h1>
                        </div>
                    </div>
                    <div><h2>Grabbing the precious baby... one moment please!</h2></div>
                </div>
            )
        } else {
            const kitten = this.props.kittens.find(kit => kit.id === parseInt(this.props.match.params.id))
            return (
                <>
                <div className="kittens">
                    <div className="home-text">
                        <h1>{kitten.name}</h1>
                    </div>
                </div>
                <KittenShow kitten={kitten} handleDeleteClick={this.handleDelete}/>
                </>
            )
        }
    }


    render() {
        return (
            <div>
                {this.handleLoading()}
            </div>
        )
    }
Enter fullscreen mode Exit fullscreen mode

Back in my KittenContainer.js, I wrote a method called handleLoading() which gives the user a loading message while the kittens are being fetched from the server.

In Conclusion

This project saw many iterations in my head. There is still a lot more that I would like to implement in the future - such as authorization for user accounts, an adoption application for community members to apply to adopt specific kittens, etc.

I have really enjoyed learning React and hope to find a job as a front-end developer in the future.

Top comments (0)