a simple frontend-only Giphy clone bootstrapped with Create React App.
To start the app, please run
npm i && npm run start
.
The home page features a loading UI and instantiates a GET request to Giphy's API to return trending gifs. From the Grid
component, or the mosaic of giphy gifs, users can click on any gif, opening a modal that displays a larger version of the gif as well as information about it and the option to add it to favorites.
The search input allows users to do a text-based search of Giphy gifs, returning those whose title includes the searched-for word.
After clicking on a gif from the grid/mosaic, users can add the selected gif to their favorites from within the displayed modal. The user's favorite gifs are saved in their browser cookies and can be viewed from the Favorites page.
I used redux to manage global state and to allow me to implement a sort of state flow that provides a few key features:
- clear chronological delineation of action events (in development environment, logged via
redux-logger
) - connect global state to react components via
connect
, allowing implementation of loading and error UI (seeGrid
component) - easy setup with
redux-saga
to synchronize and observe asynchronous actions
// the giphy reducer's actions, each of which updates the global state, which is propagated down to connected React components for conditional rendering (of data, loading UI, error UI, etc.)
function giphyReducer(state = initialState, action) {
switch (action.type) {
case ACTION_LOAD_GIPHY_LIST_STARTED:
return {
...state,
isLoadingList: true,
isLoadedList: false,
listLoadError: null,
};
case ACTION_LOAD_GIPHY_LIST_SUCCESS:
return {
...state,
list: action.payload.list,
isLoadingList: false,
isLoadedList: true,
};
case ACTION_LOAD_GIPHY_LIST_ERROR:
return {
...state,
isLoadingList: false,
isLoadedList: false,
listLoadError: action.payload.error,
};
default:
return state;
}
}
Sagas are, like thunks
, a way to turn redux actions into functions. Using generator functions with yield
and redux-sagas
's provided actions provide a relatively straightforward way to instantiate event "sagas" or chains while setting certain permissions from the get-go, such as whether concurrent calls are allowed.
// an example generator function that loads giphy data, calling redux actions along the way in a seemingly synchronous manner
function* handleLoadGiphyListRequested(action) {
// start generator function
// this could be used to set up loading UI, or to prevent subsequent similar calls from taking place, based on an isLoading/isStarted field
yield put(makeAction(ACTION_LOAD_GIPHY_LIST_STARTED));
try {
const list = yield fetchGiphyList();
// end function via SUCCESS or ERROR action
yield put(makeAction(ACTION_LOAD_GIPHY_LIST_SUCCESS, {
list: list,
}));
} catch (error) {
yield put(makeAction(ACTION_LOAD_GIPHY_LIST_ERROR, {
error: error,
}));
}
}
Setting up
redux
withredux-saga
would now allow me to easily build more features into the app. Although the setup was somewhat time-consuming, it's ultimately worth the effort for the ease of use moving forward.
I used JS-Cookie
to as a means to store selected favorite gif ids in the user's browser cookies:
Cookies.get('favoriteGifIds');
Cookies.set('favoriteGifIds', [gifId]);
The set
method above essentially sets a cookie key/value pair, turning the second argument into stringified JSON. Assuming a stringified array has been set
, using the get
method requires parsing the return value before utilizing it in the Giphy search API query.
async function fetchGiphyList({ favoriteGifIds }) {
// add favorite gif ids if on favorites page
if (favoriteGifIds) {
const favoriteGifIdsStr = favoriteGifIds.join(',');
giphyApiUrl += `&ids=${favoriteGifIdsStr}`;
}
// make giphy api call with updated search query string
}
- add pagination/infinite scroll on Home and Search pages! This could be done relatively easily with redux and a slightly improved
fetchGiphyList
function (seeredux/sagas/giphy
) - add unit tests for various Giphy API functions, including different GETS (trending, search), and for pagination (utilizing
offset
andlimit
query strings) - add a sort mechanism that allows user to sort by gif's upload time (ascending or descending)
- add a mechanism that allows user to search based on giphy rating (g, pg, r, etc.)
- improve the mosaic grid system!! The forced squares is an inelegant solution :( Giphy's site, however, is not mobile responsive