This project is based off of the Readable API Server starting template which contained the code for the backend api server that is interacted with for the development of the project.
The project makes the decision to combine the api-server and frontend application into one central project for both ease of development and management of source control. Each individual project, api-server and frontend, maintain their own dependencies and are tied together by npm scripts found at the root of the project.
The project makes the purposeful decision of grouping reusable components into a common controls directory which are all exported by the root index.js file for each of locating assets. An example of this can be found below:
import {
PostDetailPage,
PostCommentPage,
FullPageDialog,
PostForm,
CommentForm
} from '../components/controls'
- clone the repo
- setup projects and dependencies
yarn install
- start the backend and development server
yarn start
Overall the layout and design of the app is typical for react, redux, react-router apps. The major difference that may be noted is the concise effort to maintain reducers that are more deterministic and easily testable by removing switch and if statements and relying specifically on language features to maximize testability and determinism.
I am unsure if this deterministic reducer style is worth maintaining but felt it was interesting to try out for this project. An example is found below:
//all functions exported for testing purposes
export const loadPosts = (state, {posts})=>posts;
export const loadPostsForCategory = (state, {posts})=>([
...state.filter(item=>posts[0] && posts[0].category && item.category !== posts[0].category),
//this is a null guard for the spread operator to ensure proper array shape on the event of a null object
...(posts || [])
]);
export const addPost = (state, {post})=>([
...state,
post
]);
export const editPost = (state, {post})=>([
...state.filter(item=>post && item.id !== post.id),
//this is a null guard for the spread operator to ensure proper array shape on the event of a null object
...(post && [post] || []) // eslint-disable-line no-mixed-operators
]);
const reducer = {
[LOAD_ALL_POSTS]: loadPosts,
[LOAD_POSTS_FOR_CATEGORY]: loadPostsForCategory,
[LOAD_POST]: editPost,
[ADD_POST]: addPost,
[EDIT_POST]: editPost,
[UPVOTE_POST]: editPost,
[DOWNVOTE_POST]: editPost,
[DELETE_POST]: editPost
};
export default (state=[], {type, ...action})=>
reducer[type] ? reducer[type](state, action) : state;
Information about the API server and how to use it can be found in its README file.
This repository is used for a nanodegree program that I am participating in so I will not be accepting pull requests.