diff options
Diffstat (limited to 'src/features/counter')
-rw-r--r-- | src/features/counter/Counter.jsx | 63 | ||||
-rw-r--r-- | src/features/counter/Counter.module.css | 78 | ||||
-rw-r--r-- | src/features/counter/counterAPI.js | 6 | ||||
-rw-r--r-- | src/features/counter/counterSlice.js | 68 | ||||
-rw-r--r-- | src/features/counter/counterSlice.spec.js | 33 |
5 files changed, 22 insertions, 226 deletions
diff --git a/src/features/counter/Counter.jsx b/src/features/counter/Counter.jsx index 37d866d..d589bf9 100644 --- a/src/features/counter/Counter.jsx +++ b/src/features/counter/Counter.jsx @@ -1,67 +1,28 @@ -import React, { useState } from "react"; -import { useSelector, useDispatch } from "react-redux"; -import { - decrement, - increment, - incrementByAmount, - incrementAsync, - incrementIfOdd, - selectCount, -} from "./counterSlice"; -import styles from "./Counter.module.css"; +import React from 'react' +import { useSelector, useDispatch } from 'react-redux' +import { decrement, increment } from './counterSlice' export function Counter() { - const count = useSelector(selectCount); - const dispatch = useDispatch(); - const [incrementAmount, setIncrementAmount] = useState("2"); - - const incrementValue = Number(incrementAmount) || 0; + const count = useSelector((state) => state.counter.value) + const dispatch = useDispatch() return ( <div> - <div className={styles.row}> - <button - className={styles.button} - aria-label="Decrement value" - onClick={() => dispatch(decrement())} - > - - - </button> - <span className={styles.value}>{count}</span> + <div> <button - className={styles.button} aria-label="Increment value" onClick={() => dispatch(increment())} > - + + Increment </button> - </div> - <div className={styles.row}> - <input - className={styles.textbox} - aria-label="Set increment amount" - value={incrementAmount} - onChange={(e) => setIncrementAmount(e.target.value)} - /> + <span>{count}</span> <button - className={styles.button} - onClick={() => dispatch(incrementByAmount(incrementValue))} - > - Add Amount - </button> - <button - className={styles.asyncButton} - onClick={() => dispatch(incrementAsync(incrementValue))} - > - Add Async - </button> - <button - className={styles.button} - onClick={() => dispatch(incrementIfOdd(incrementValue))} + aria-label="Decrement value" + onClick={() => dispatch(decrement())} > - Add If Odd + Decrement </button> </div> </div> - ); + ) } diff --git a/src/features/counter/Counter.module.css b/src/features/counter/Counter.module.css deleted file mode 100644 index 9e70f8e..0000000 --- a/src/features/counter/Counter.module.css +++ /dev/null @@ -1,78 +0,0 @@ -.row { - display: flex; - align-items: center; - justify-content: center; -} - -.row > button { - margin-left: 4px; - margin-right: 8px; -} -.row:not(:last-child) { - margin-bottom: 16px; -} - -.value { - font-size: 78px; - padding-left: 16px; - padding-right: 16px; - margin-top: 2px; - font-family: "Courier New", Courier, monospace; -} - -.button { - appearance: none; - background: none; - font-size: 32px; - padding-left: 12px; - padding-right: 12px; - outline: none; - border: 2px solid transparent; - color: rgb(112, 76, 182); - padding-bottom: 4px; - cursor: pointer; - background-color: rgba(112, 76, 182, 0.1); - border-radius: 2px; - transition: all 0.15s; -} - -.textbox { - font-size: 32px; - padding: 2px; - width: 64px; - text-align: center; - margin-right: 4px; -} - -.button:hover, -.button:focus { - border: 2px solid rgba(112, 76, 182, 0.4); -} - -.button:active { - background-color: rgba(112, 76, 182, 0.2); -} - -.asyncButton { - composes: button; - position: relative; -} - -.asyncButton:after { - content: ""; - background-color: rgba(112, 76, 182, 0.15); - display: block; - position: absolute; - width: 100%; - height: 100%; - left: 0; - top: 0; - opacity: 0; - transition: width 1s linear, opacity 0.5s ease 1s; -} - -.asyncButton:active:after { - width: 0%; - opacity: 1; - transition: 0s; -} diff --git a/src/features/counter/counterAPI.js b/src/features/counter/counterAPI.js deleted file mode 100644 index cc9b4a4..0000000 --- a/src/features/counter/counterAPI.js +++ /dev/null @@ -1,6 +0,0 @@ -// A mock function to mimic making an async request for data -export function fetchCount(amount = 1) { - return new Promise((resolve) => - setTimeout(() => resolve({ data: amount }), 500) - ); -} diff --git a/src/features/counter/counterSlice.js b/src/features/counter/counterSlice.js index a9441ac..4cb9993 100644 --- a/src/features/counter/counterSlice.js +++ b/src/features/counter/counterSlice.js @@ -1,29 +1,10 @@ -import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"; -import { fetchCount } from "./counterAPI"; - -const initialState = { - value: 0, - status: "idle", -}; - -// The function below is called a thunk and allows us to perform async logic. It -// can be dispatched like a regular action: `dispatch(incrementAsync(10))`. This -// will call the thunk with the `dispatch` function as the first argument. Async -// code can then be executed and other actions can be dispatched. Thunks are -// typically used to make async requests. -export const incrementAsync = createAsyncThunk( - "counter/fetchCount", - async (amount) => { - const response = await fetchCount(amount); - // The value we return becomes the `fulfilled` action payload - return response.data; - } -); +import { createSlice } from '@reduxjs/toolkit' export const counterSlice = createSlice({ - name: "counter", - initialState, - // The `reducers` field lets us define reducers and generate associated actions + name: 'counter', + initialState: { + value: 0, + }, reducers: { increment: (state) => { // Redux Toolkit allows us to write "mutating" logic in reducers. It @@ -34,40 +15,11 @@ export const counterSlice = createSlice({ }, decrement: (state) => { state.value -= 1; - }, - // Use the PayloadAction type to declare the contents of `action.payload` - incrementByAmount: (state, action) => { - state.value += action.payload; - }, - }, - // The `extraReducers` field lets the slice handle actions defined elsewhere, - // including actions generated by createAsyncThunk or in other slices. - extraReducers: (builder) => { - builder - .addCase(incrementAsync.pending, (state) => { - state.status = "loading"; - }) - .addCase(incrementAsync.fulfilled, (state, action) => { - state.status = "idle"; - state.value += action.payload; - }); + } }, -}); - -export const { increment, decrement, incrementByAmount } = counterSlice.actions; - -// The function below is called a selector and allows us to select a value from -// the state. Selectors can also be defined inline where they're used instead of -// in the slice file. For example: `useSelector((state: RootState) => state.counter.value)` -export const selectCount = (state) => state.counter.value; +}) -// We can also write thunks by hand, which may contain both sync and async logic. -// Here's an example of conditionally dispatching actions based on current state. -export const incrementIfOdd = (amount) => (dispatch, getState) => { - const currentValue = selectCount(getState()); - if (currentValue % 2 === 1) { - dispatch(incrementByAmount(amount)); - } -}; +// Action creators are generated for each case reducer function +export const { increment, decrement } = counterSlice.actions -export default counterSlice.reducer; +export default counterSlice.reducer diff --git a/src/features/counter/counterSlice.spec.js b/src/features/counter/counterSlice.spec.js deleted file mode 100644 index 113526b..0000000 --- a/src/features/counter/counterSlice.spec.js +++ /dev/null @@ -1,33 +0,0 @@ -import counterReducer, { - increment, - decrement, - incrementByAmount, -} from "./counterSlice"; - -describe("counter reducer", () => { - const initialState = { - value: 3, - status: "idle", - }; - it("should handle initial state", () => { - expect(counterReducer(undefined, { type: "unknown" })).toEqual({ - value: 0, - status: "idle", - }); - }); - - it("should handle increment", () => { - const actual = counterReducer(initialState, increment()); - expect(actual.value).toEqual(4); - }); - - it("should handle decrement", () => { - const actual = counterReducer(initialState, decrement()); - expect(actual.value).toEqual(2); - }); - - it("should handle incrementByAmount", () => { - const actual = counterReducer(initialState, incrementByAmount(2)); - expect(actual.value).toEqual(5); - }); -}); |