Skip to content

Commit

Permalink
#9 Add count persistence
Browse files Browse the repository at this point in the history
  • Loading branch information
James Humphreys authored Sep 14, 2022
1 parent 3a11332 commit 08c3beb
Show file tree
Hide file tree
Showing 7 changed files with 53 additions and 14 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,6 @@
/node_modules
/build
.DS_Store
/cypress/downloads
/cypress/screenshots
/cypress/videos
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ This is a simple React based counter app to allow a user to increment, decrement
- CSS in JS styling using emotion
- Replicating a basic Redux style store using a JavaScript reducer along with React `useReducer` hook.
- Sharing the global state and reducer actions to the application component tree using React `useContext` hook
- Persisting the count value using browser localStorage API
- Dark mode support using `prefers-color-scheme` media query
- Husky pre-commit hooks for linting and formatting
- Husky pre-commit hooks for linting and formatting or source-code
- GitHub actions for CI / CD pipelines
- End to End testing using Cypress

## Getting started

Expand Down Expand Up @@ -78,6 +80,14 @@ Pre-commit hooks will run using Husky to:
- Lint all committed source (js, jsx, ts, tsx) using ESLint rules
- Format all known filetypes using Prettier

### Testing

Tests can be run (end to end) using [Cypress](https://www.cypress.io/). **Note:** An instance of the application must be running for the test suite to function; run `npm run start` ensuring the default port of `3000` is used.

```bash
npm run test
```

## Deployment

To build a production copy for deployment `cd` into the project root and run the below command from your terminal. **Note:** The build will be performed as per the `homepage` key in `package.json`.
Expand Down
10 changes: 10 additions & 0 deletions cypress/e2e/app.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,16 @@ describe("React Counter App", () => {
cy.get("@countValue").should("contain", "0");
});

it("persists count changes", () => {
cy.get("@incrementValue").click();
cy.get("@incrementValue").click();
cy.get("@countValue").should("contain", "2");
cy.get("@decrementValue").click();
cy.get("@countValue").should("contain", "1");
cy.reload();
cy.get("@countValue").should("contain", "1");
});

it("prevents a user reseting the count value when zero", () => {
cy.get("@resetValue").should("be.disabled");
});
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-counter-app",
"version": "1.11.2",
"version": "1.12.0",
"description": "React counter app",
"engines": {
"node": ">=16.15.1 <17.0.0"
Expand Down Expand Up @@ -54,6 +54,7 @@
"check-formatting": "prettier --check 'src/**/*.{ts,tsx}'",
"fix-formatting": "npm run check-formatting -- --write",
"test": "cypress open",
"test:headless": "cypress run",
"eject": "react-scripts eject"
},
"browserslist": [
Expand Down
2 changes: 1 addition & 1 deletion src/app/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const Button = styled.button({
"&:not([disabled])": {
cursor: "pointer",

"&:hover, &:focus": {
"&:hover": {
opacity: "0.9",
},
},
Expand Down
33 changes: 24 additions & 9 deletions src/app/counter-provider.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useContext, useReducer } from "react";
import React, { useContext, useEffect, useReducer } from "react";

const counterActionTypes = {
INCREMENT: "INCREMENT",
Expand Down Expand Up @@ -38,13 +38,32 @@ interface counterReducerActions {
reset: () => void;
}

function useLocalStorageCountValue(
key: string,
defaultValue: number
): [number, (value: number) => void] {
const value = localStorage.getItem(key)
? Number(localStorage.getItem(key))
: defaultValue;

return [
value,
(value: number) => localStorage.setItem(key, value.toString()),
];
}

function useCounterReducer(): {
count: number;
actions: counterReducerActions;
} {
const initialState = { count: initialCount };
const [localStorageCountValue, setLocalStorageCountValue] =
useLocalStorageCountValue("binaryJimCounterAppValue", initialCount);

const [state, dispatch] = useReducer(counterReducer, initialState);
const [state, dispatch] = useReducer(
counterReducer,
localStorageCountValue,
(count) => ({ count })
);

const count = state.count;

Expand All @@ -54,13 +73,9 @@ function useCounterReducer(): {
reset: () => dispatch({ type: counterActionTypes.RESET }),
};

/*
For later enhancement to add local storage persistance, much like redux "store.subscribe"
useEffect(() => {
console.log('Count changed')
}, [state.count])
*/
setLocalStorageCountValue(count);
}, [count, setLocalStorageCountValue]);

return { count, actions };
}
Expand Down

0 comments on commit 08c3beb

Please sign in to comment.