From 10a6b3918f94b84173a7ff904de0338facb1fc51 Mon Sep 17 00:00:00 2001 From: GUAJEGUICHAN Date: Tue, 21 Dec 2021 21:05:50 +0900 Subject: [PATCH 01/14] =?UTF-8?q?[refactor]=20=EA=B4=80=EC=8B=AC=EC=82=AC?= =?UTF-8?q?=EC=9D=98=20=EB=B6=84=EB=A6=AC=20deleteTask,=20addTask,=20updat?= =?UTF-8?q?eTaskTitle=20=ED=95=A8=EC=88=98=20=EB=A7=8C=EB=93=A4=EC=96=B4?= =?UTF-8?q?=EC=84=9C=20App=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=EC=99=80=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC=EC=8B=9C=ED=82=A4=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 212 +++++++++++++++++++++++++++++++++++++++++----- package.json | 4 +- src/App.jsx | 56 +++++++----- 3 files changed, 228 insertions(+), 44 deletions(-) diff --git a/package-lock.json b/package-lock.json index 47281602d..ddf35b9b0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,9 @@ "license": "ISC", "dependencies": { "react": "^17.0.2", - "react-dom": "^17.0.2" + "react-dom": "^17.0.2", + "react-redux": "^7.2.6", + "redux": "^4.1.2" }, "devDependencies": { "@babel/core": "^7.14.2", @@ -1374,12 +1376,14 @@ } }, "node_modules/@babel/runtime": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.0.tgz", - "integrity": "sha512-JELkvo/DlpNdJ7dlyw/eY7E0suy5i5GQH+Vlxaq1nsNJ+H7f4Vtv3jMeCEgRhZZQFXTjldYfQgv2qmM6M1v5wA==", - "dev": true, + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.5.tgz", + "integrity": "sha512-TXWihFIS3Pyv5hzR7j6ihmeLkZfrXGxAr5UfSl8CHf+6q/wpiYDkUau0czckpYG8QmnCIuPpdLtuA9VmuGGyMA==", "dependencies": { "regenerator-runtime": "^0.13.4" + }, + "engines": { + "node": ">=6.9.0" } }, "node_modules/@babel/runtime-corejs3": { @@ -2527,6 +2531,15 @@ "@types/node": "*" } }, + "node_modules/@types/hoist-non-react-statics": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", + "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", + "dependencies": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", @@ -2597,6 +2610,37 @@ "integrity": "sha512-PijRCG/K3s3w1We6ynUKdxEc5AcuuH3NBmMDP8uvKVp6X43UY7NQlTzczakXP3DJR0F4dfNQIGjU2cUeRYs2AA==", "dev": true }, + "node_modules/@types/prop-types": { + "version": "15.7.4", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz", + "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==" + }, + "node_modules/@types/react": { + "version": "17.0.37", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.37.tgz", + "integrity": "sha512-2FS1oTqBGcH/s0E+CjrCCR9+JMpsu9b69RTFO+40ua43ZqP5MmQ4iUde/dMjWR909KxZwmOQIFq6AV6NjEG5xg==", + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-redux": { + "version": "7.1.20", + "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.20.tgz", + "integrity": "sha512-q42es4c8iIeTgcnB+yJgRTTzftv3eYYvCZOh1Ckn2eX/3o5TdsQYKUWpLoLuGlcY/p+VAhV9IOEZJcWk/vfkXw==", + "dependencies": { + "@types/hoist-non-react-statics": "^3.3.0", + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0", + "redux": "^4.0.0" + } + }, + "node_modules/@types/scheduler": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" + }, "node_modules/@types/stack-utils": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz", @@ -4711,6 +4755,11 @@ "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", "dev": true }, + "node_modules/csstype": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz", + "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==" + }, "node_modules/cucumber-expressions": { "version": "6.6.2", "resolved": "https://registry.npmjs.org/cucumber-expressions/-/cucumber-expressions-6.6.2.tgz", @@ -7361,6 +7410,19 @@ "he": "bin/he" } }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, "node_modules/hosted-git-info": { "version": "2.8.9", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", @@ -12640,7 +12702,6 @@ "version": "15.7.2", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", - "dev": true, "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -12650,8 +12711,7 @@ "node_modules/prop-types/node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "node_modules/proto-list": { "version": "1.2.4", @@ -12884,8 +12944,31 @@ "node_modules/react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" + }, + "node_modules/react-redux": { + "version": "7.2.6", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.6.tgz", + "integrity": "sha512-10RPdsz0UUrRL1NZE0ejTkucnclYSgXp5q+tB5SWx2qeG2ZJQJyymgAhwKy73yiL/13btfB6fPr+rgbMAaZIAQ==", + "dependencies": { + "@babel/runtime": "^7.15.4", + "@types/react-redux": "^7.1.20", + "hoist-non-react-statics": "^3.3.2", + "loose-envify": "^1.4.0", + "prop-types": "^15.7.2", + "react-is": "^17.0.2" + }, + "peerDependencies": { + "react": "^16.8.3 || ^17" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } }, "node_modules/read-pkg": { "version": "3.0.0", @@ -13032,6 +13115,14 @@ "node": ">=8" } }, + "node_modules/redux": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.1.2.tgz", + "integrity": "sha512-SH8PglcebESbd/shgf6mii6EIoRM0zrQyjcuQ+ojmfxjTtE0z9Y8pa62iA/OJ58qjP6j27uyW4kUF4jl/jd6sw==", + "dependencies": { + "@babel/runtime": "^7.9.2" + } + }, "node_modules/regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -13053,8 +13144,7 @@ "node_modules/regenerator-runtime": { "version": "0.13.7", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", - "dev": true + "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" }, "node_modules/regenerator-transform": { "version": "0.14.5", @@ -18445,10 +18535,9 @@ } }, "@babel/runtime": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.0.tgz", - "integrity": "sha512-JELkvo/DlpNdJ7dlyw/eY7E0suy5i5GQH+Vlxaq1nsNJ+H7f4Vtv3jMeCEgRhZZQFXTjldYfQgv2qmM6M1v5wA==", - "dev": true, + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.5.tgz", + "integrity": "sha512-TXWihFIS3Pyv5hzR7j6ihmeLkZfrXGxAr5UfSl8CHf+6q/wpiYDkUau0czckpYG8QmnCIuPpdLtuA9VmuGGyMA==", "requires": { "regenerator-runtime": "^0.13.4" } @@ -19371,6 +19460,15 @@ "@types/node": "*" } }, + "@types/hoist-non-react-statics": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", + "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", + "requires": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, "@types/istanbul-lib-coverage": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", @@ -19441,6 +19539,37 @@ "integrity": "sha512-PijRCG/K3s3w1We6ynUKdxEc5AcuuH3NBmMDP8uvKVp6X43UY7NQlTzczakXP3DJR0F4dfNQIGjU2cUeRYs2AA==", "dev": true }, + "@types/prop-types": { + "version": "15.7.4", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz", + "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==" + }, + "@types/react": { + "version": "17.0.37", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.37.tgz", + "integrity": "sha512-2FS1oTqBGcH/s0E+CjrCCR9+JMpsu9b69RTFO+40ua43ZqP5MmQ4iUde/dMjWR909KxZwmOQIFq6AV6NjEG5xg==", + "requires": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "@types/react-redux": { + "version": "7.1.20", + "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.20.tgz", + "integrity": "sha512-q42es4c8iIeTgcnB+yJgRTTzftv3eYYvCZOh1Ckn2eX/3o5TdsQYKUWpLoLuGlcY/p+VAhV9IOEZJcWk/vfkXw==", + "requires": { + "@types/hoist-non-react-statics": "^3.3.0", + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0", + "redux": "^4.0.0" + } + }, + "@types/scheduler": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" + }, "@types/stack-utils": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz", @@ -21155,6 +21284,11 @@ } } }, + "csstype": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz", + "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==" + }, "cucumber-expressions": { "version": "6.6.2", "resolved": "https://registry.npmjs.org/cucumber-expressions/-/cucumber-expressions-6.6.2.tgz", @@ -23220,6 +23354,21 @@ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true }, + "hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "requires": { + "react-is": "^16.7.0" + }, + "dependencies": { + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + } + } + }, "hosted-git-info": { "version": "2.8.9", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", @@ -27259,7 +27408,6 @@ "version": "15.7.2", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", - "dev": true, "requires": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -27269,8 +27417,7 @@ "react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" } } }, @@ -27465,8 +27612,20 @@ "react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" + }, + "react-redux": { + "version": "7.2.6", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.6.tgz", + "integrity": "sha512-10RPdsz0UUrRL1NZE0ejTkucnclYSgXp5q+tB5SWx2qeG2ZJQJyymgAhwKy73yiL/13btfB6fPr+rgbMAaZIAQ==", + "requires": { + "@babel/runtime": "^7.15.4", + "@types/react-redux": "^7.1.20", + "hoist-non-react-statics": "^3.3.2", + "loose-envify": "^1.4.0", + "prop-types": "^15.7.2", + "react-is": "^17.0.2" + } }, "read-pkg": { "version": "3.0.0", @@ -27579,6 +27738,14 @@ "strip-indent": "^3.0.0" } }, + "redux": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.1.2.tgz", + "integrity": "sha512-SH8PglcebESbd/shgf6mii6EIoRM0zrQyjcuQ+ojmfxjTtE0z9Y8pa62iA/OJ58qjP6j27uyW4kUF4jl/jd6sw==", + "requires": { + "@babel/runtime": "^7.9.2" + } + }, "regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -27597,8 +27764,7 @@ "regenerator-runtime": { "version": "0.13.7", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", - "dev": true + "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" }, "regenerator-transform": { "version": "0.14.5", diff --git a/package.json b/package.json index 19b40b504..96f9ac056 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,8 @@ }, "dependencies": { "react": "^17.0.2", - "react-dom": "^17.0.2" + "react-dom": "^17.0.2", + "react-redux": "^7.2.6", + "redux": "^4.1.2" } } diff --git a/src/App.jsx b/src/App.jsx index 7630c320f..70714e97f 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -2,36 +2,52 @@ import { useState } from 'react'; import Page from './Page'; -export default function App() { - const [state, setState] = useState({ - newId: 100, - taskTitle: '', - tasks: [], - }); +const initialState = { + newId: 100, + taskTitle: '', + tasks: [], +}; + +function updateTaskTitle(state, taskTitle) { + return { + ...state, + taskTitle, + }; +} +function addTask(state) { const { newId, taskTitle, tasks } = state; + return { + ...state, + newId: newId + 1, + taskTitle: '', + tasks: [...tasks, { id: newId, title: taskTitle }], + }; +} + +function deleteTask(state, id) { + const { tasks } = state; + return { + ...state, + tasks: tasks.filter((task) => task.id !== id), + }; +} + +export default function App() { + const [state, setState] = useState(initialState); + + const { taskTitle, tasks } = state; function handleChangeTitle(event) { - setState({ - ...state, - taskTitle: event.target.value, - }); + setState(updateTaskTitle(state, event.target.value)); } function handleClickAddTask() { - setState({ - ...state, - newId: newId + 1, - taskTitle: '', - tasks: [...tasks, { id: newId, title: taskTitle }], - }); + setState(addTask(state)); } function handleClickDeleteTask(id) { - setState({ - ...state, - tasks: tasks.filter((task) => task.id !== id), - }); + setState(deleteTask(state, id)); } return ( From cadf3e569c196b790a30af56c03f240cdec7fa22 Mon Sep 17 00:00:00 2001 From: GUAJEGUICHAN Date: Tue, 21 Dec 2021 22:07:00 +0900 Subject: [PATCH 02/14] =?UTF-8?q?[chore]=20dependecies=20=EC=97=85?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/package.json b/package.json index 96f9ac056..2186ccd46 100644 --- a/package.json +++ b/package.json @@ -15,28 +15,28 @@ "author": "", "license": "ISC", "devDependencies": { - "@babel/core": "^7.14.2", - "@babel/preset-env": "^7.14.2", - "@babel/preset-react": "^7.13.13", - "@testing-library/jest-dom": "^5.12.0", - "@testing-library/react": "^11.2.7", - "@types/jest": "^26.0.23", - "babel-jest": "^26.6.3", - "babel-loader": "^8.2.2", - "codeceptjs": "^3.0.7", - "eslint": "^7.26.0", - "eslint-config-airbnb": "^18.2.1", - "eslint-plugin-import": "^2.23.2", - "eslint-plugin-jsx-a11y": "^6.4.1", - "eslint-plugin-react": "^7.23.2", - "eslint-plugin-react-hooks": "^4.2.0", - "jest": "^26.6.3", + "@babel/core": "^7.16.5", + "@babel/preset-env": "^7.16.5", + "@babel/preset-react": "^7.16.5", + "@testing-library/jest-dom": "^5.16.1", + "@testing-library/react": "^12.1.2", + "@types/jest": "^27.0.3", + "babel-jest": "^27.4.5", + "babel-loader": "^8.2.3", + "codeceptjs": "^3.2.2", + "eslint": "^8.5.0", + "eslint-config-airbnb": "^19.0.2", + "eslint-plugin-import": "^2.25.3", + "eslint-plugin-jsx-a11y": "^6.5.1", + "eslint-plugin-react": "^7.27.1", + "eslint-plugin-react-hooks": "^4.3.0", + "jest": "^27.4.5", "jest-plugin-context": "^2.9.0", - "puppeteer": "^9.1.1", - "start-server-and-test": "^1.12.2", - "webpack": "^5.37.0", - "webpack-cli": "^4.7.0", - "webpack-dev-server": "^3.11.2" + "puppeteer": "^13.0.0", + "start-server-and-test": "^1.14.0", + "webpack": "^5.65.0", + "webpack-cli": "^4.9.1", + "webpack-dev-server": "^4.6.0" }, "dependencies": { "react": "^17.0.2", From 988814e78ac8b6b3376a0e1e58e7947715574ba4 Mon Sep 17 00:00:00 2001 From: GUAJEGUICHAN Date: Tue, 21 Dec 2021 22:46:01 +0900 Subject: [PATCH 03/14] =?UTF-8?q?[refactor]useSelector,=20dispatch,=20acti?= =?UTF-8?q?on=20=EA=B5=AC=ED=98=84=20useSelector=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=9B=90=ED=95=98=EB=8A=94=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=20dispatch=EB=A1=9C=20action=20=EC=A0=84?= =?UTF-8?q?=EB=8B=AC=EC=82=AC=EC=9A=A9=20=EA=B4=80=EC=8B=AC=EC=82=AC=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC=EB=A1=9C=20=EB=B9=BC=EB=86=93=EC=9D=80=20?= =?UTF-8?q?=ED=95=A8=EC=88=98=EB=93=A4=EC=9D=84=20action=EB=A1=9C=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.jsx | 49 ++++++++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index 70714e97f..c82318529 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,4 +1,4 @@ -import { useState } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; import Page from './Page'; @@ -8,46 +8,53 @@ const initialState = { tasks: [], }; -function updateTaskTitle(state, taskTitle) { +function updateTaskTitle(taskTitle) { return { - ...state, - taskTitle, + type: 'updateTaskTitle', + payload: { + taskTitle, + }, }; } -function addTask(state) { - const { newId, taskTitle, tasks } = state; +function addTask() { return { - ...state, - newId: newId + 1, - taskTitle: '', - tasks: [...tasks, { id: newId, title: taskTitle }], + type: 'addTask', + }; } -function deleteTask(state, id) { - const { tasks } = state; +function deleteTask(id) { return { - ...state, - tasks: tasks.filter((task) => task.id !== id), + type: 'deleteTask', + payload: { + id, + }, + + }; +} +function selector(state) { + return { + taskTitle: state.taskTitle, + tasks: state.tasks, }; } - export default function App() { - const [state, setState] = useState(initialState); - - const { taskTitle, tasks } = state; + // const [state, setState] = useState(initialState); + const { taskTitle, tasks } = useSelector(selector); + const dispatch = useDispatch(); function handleChangeTitle(event) { - setState(updateTaskTitle(state, event.target.value)); + console.log(event.target.value); + dispatch(updateTaskTitle(event.target.value)); } function handleClickAddTask() { - setState(addTask(state)); + dispatch(addTask()); } function handleClickDeleteTask(id) { - setState(deleteTask(state, id)); + dispatch(deleteTask(id)); } return ( From 7f886067d937ebfdb11c583aea81d45fc185940c Mon Sep 17 00:00:00 2001 From: GUAJEGUICHAN Date: Tue, 21 Dec 2021 22:46:41 +0900 Subject: [PATCH 04/14] =?UTF-8?q?[refactor]=20reducer=EA=B5=AC=ED=98=84=20?= =?UTF-8?q?=EC=95=A1=EC=85=98=EC=97=90=20=EB=A7=9E=EC=B6=B0=EC=84=9C=20?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/store.js | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 src/store.js diff --git a/src/store.js b/src/store.js new file mode 100644 index 000000000..da2f7a82b --- /dev/null +++ b/src/store.js @@ -0,0 +1,40 @@ +import { createStore } from 'redux'; + +const initialState = { + newId: 100, + taskTitle: '', + tasks: [], +}; + +function reducer(state = initialState, action) { + if (action.type === 'updateTaskTitle') { + return { + ...state, + taskTitle: action.payload.taskTitle, + }; + } + if (action.type === 'addTask') { + const { newId, taskTitle, tasks } = state; + + return { + ...state, + newId: newId + 1, + taskTitle: '', + tasks: [...tasks, { id: newId, title: taskTitle }], + }; + } + if (action.type === 'deleteTask') { + const { tasks } = state; + + return { + ...state, + tasks: tasks.filter((task) => task.id !== action.payload.id), + }; + } + + return state; +} + +const store = createStore(reducer); + +export default store; From 35da66e55891937edc4b07a14aafe89c14d6f1d9 Mon Sep 17 00:00:00 2001 From: GUAJEGUICHAN Date: Tue, 21 Dec 2021 22:47:51 +0900 Subject: [PATCH 05/14] =?UTF-8?q?[feature]=20react-redux=EB=A1=9C=20?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EA=B4=80=EB=A6=AC=ED=95=98?= =?UTF-8?q?=EB=A0=A4=EB=A9=B4=20Provier=EB=A1=9C=20=EA=B0=90=EC=8B=B8?= =?UTF-8?q?=EC=95=BC=ED=95=9C=EB=8B=A4.=20=EA=B4=80=EB=A6=AC=ED=95=A0=20?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=84=B0=EC=9D=B8=20store=EB=8A=94=20props?= =?UTF-8?q?=EB=A1=9C=20=EC=A0=84=EB=8B=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/index.jsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/index.jsx b/src/index.jsx index 5752f9375..12de19b87 100644 --- a/src/index.jsx +++ b/src/index.jsx @@ -1,8 +1,16 @@ import ReactDOM from 'react-dom'; +import { Provider } from 'react-redux'; import App from './App'; +import store from './store'; + ReactDOM.render( - , + ( + + + + ) + , document.getElementById('app'), ); From d8fea3c1d0efba1d780bd97ab86fdfe8062e795d Mon Sep 17 00:00:00 2001 From: GUAJEGUICHAN Date: Tue, 21 Dec 2021 22:52:26 +0900 Subject: [PATCH 06/14] =?UTF-8?q?[test]=20test=ED=86=B5=EA=B3=BC=ED=95=98?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20useSelector=20=EA=B0=80=EC=A7=9C=ED=95=A8?= =?UTF-8?q?=EC=88=98=20=EC=9D=B4=EC=9A=A9=20jest.mock('react-redux')?= =?UTF-8?q?=EB=A1=9C=20react-router=20=EB=AA=A8=EB=93=88=EC=9D=84=20mock?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=A7=8C=EB=93=A4=EC=97=88=EB=8B=A4.=20?= =?UTF-8?q?=EA=B7=B8=EB=9E=98=EC=84=9C=20=ED=95=98=EC=9C=84=20=ED=95=A8?= =?UTF-8?q?=EC=88=98=EB=93=A4=EC=9D=84=20=EB=AA=A8=EB=91=90=20mock?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=A7=8C=EB=93=A4=EC=97=88=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 13번줄 userSelector.mockImplemention() 로 selector함수 받아서 tasks 데이터 받고 가짜 useSelector을 실행시킨다. --- src/App.test.jsx | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/App.test.jsx b/src/App.test.jsx index 3b7c1a886..e2bfcf6d4 100644 --- a/src/App.test.jsx +++ b/src/App.test.jsx @@ -1,8 +1,19 @@ import { render } from '@testing-library/react'; +import { useSelector } from 'react-redux'; import App from './App'; +jest.mock('react-redux'); + test('App', () => { + const tasks = [ + { id: 100, title: '숨 쉬기' }, + ]; + + useSelector.mockImplementation((selector) => selector({ + tasks, + })); + const { getByText } = render(( )); From dcf5df1b81934d3f12f264167fa1072f98acd4f9 Mon Sep 17 00:00:00 2001 From: GUAJEGUICHAN Date: Wed, 22 Dec 2021 02:29:12 +0900 Subject: [PATCH 07/14] =?UTF-8?q?[refactor]=20action.js=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.jsx | 33 +-------------------------------- src/action.js | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 32 deletions(-) create mode 100644 src/action.js diff --git a/src/App.jsx b/src/App.jsx index c82318529..2868d9181 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,38 +1,8 @@ import { useDispatch, useSelector } from 'react-redux'; +import { addTask, deleteTask, updateTaskTitle } from './action'; import Page from './Page'; -const initialState = { - newId: 100, - taskTitle: '', - tasks: [], -}; - -function updateTaskTitle(taskTitle) { - return { - type: 'updateTaskTitle', - payload: { - taskTitle, - }, - }; -} - -function addTask() { - return { - type: 'addTask', - - }; -} - -function deleteTask(id) { - return { - type: 'deleteTask', - payload: { - id, - }, - - }; -} function selector(state) { return { taskTitle: state.taskTitle, @@ -45,7 +15,6 @@ export default function App() { const dispatch = useDispatch(); function handleChangeTitle(event) { - console.log(event.target.value); dispatch(updateTaskTitle(event.target.value)); } diff --git a/src/action.js b/src/action.js new file mode 100644 index 000000000..59ab9c3e3 --- /dev/null +++ b/src/action.js @@ -0,0 +1,25 @@ +export function updateTaskTitle(taskTitle) { + return { + type: 'updateTaskTitle', + payload: { + taskTitle, + }, + }; +} + +export function addTask() { + return { + type: 'addTask', + + }; +} + +export function deleteTask(id) { + return { + type: 'deleteTask', + payload: { + id, + }, + + }; +} From e3afcb5226990c8c76f633ffbe16623f11c1788c Mon Sep 17 00:00:00 2001 From: GUAJEGUICHAN Date: Wed, 22 Dec 2021 14:13:58 +0900 Subject: [PATCH 08/14] =?UTF-8?q?[refactor]=20store.js=EC=97=90=EC=84=9C?= =?UTF-8?q?=20reducer.js=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/action.js | 1 - src/reducer.js | 34 ++++++++++++++++++++++++++++++++++ src/store.js | 36 +----------------------------------- 3 files changed, 35 insertions(+), 36 deletions(-) create mode 100644 src/reducer.js diff --git a/src/action.js b/src/action.js index 59ab9c3e3..27c253c25 100644 --- a/src/action.js +++ b/src/action.js @@ -20,6 +20,5 @@ export function deleteTask(id) { payload: { id, }, - }; } diff --git a/src/reducer.js b/src/reducer.js new file mode 100644 index 000000000..7a5758c1a --- /dev/null +++ b/src/reducer.js @@ -0,0 +1,34 @@ +const initialState = { + newId: 100, + taskTitle: '', + tasks: [], +}; + +export default function reducer(state = initialState, action) { + if (action.type === 'updateTaskTitle') { + return { + ...state, + taskTitle: action.payload.taskTitle, + }; + } + if (action.type === 'addTask') { + const { newId, taskTitle, tasks } = state; + + return { + ...state, + newId: newId + 1, + taskTitle: '', + tasks: [...tasks, { id: newId, title: taskTitle }], + }; + } + if (action.type === 'deleteTask') { + const { tasks } = state; + + return { + ...state, + tasks: tasks.filter((task) => task.id !== action.payload.id), + }; + } + + return state; +} diff --git a/src/store.js b/src/store.js index da2f7a82b..0683c698e 100644 --- a/src/store.js +++ b/src/store.js @@ -1,39 +1,5 @@ import { createStore } from 'redux'; - -const initialState = { - newId: 100, - taskTitle: '', - tasks: [], -}; - -function reducer(state = initialState, action) { - if (action.type === 'updateTaskTitle') { - return { - ...state, - taskTitle: action.payload.taskTitle, - }; - } - if (action.type === 'addTask') { - const { newId, taskTitle, tasks } = state; - - return { - ...state, - newId: newId + 1, - taskTitle: '', - tasks: [...tasks, { id: newId, title: taskTitle }], - }; - } - if (action.type === 'deleteTask') { - const { tasks } = state; - - return { - ...state, - tasks: tasks.filter((task) => task.id !== action.payload.id), - }; - } - - return state; -} +import reducer from './reducer'; const store = createStore(reducer); From 6758f1b8b9d6c019e751db67d17f2bd74e398c19 Mon Sep 17 00:00:00 2001 From: GUAJEGUICHAN Date: Wed, 22 Dec 2021 14:37:17 +0900 Subject: [PATCH 09/14] =?UTF-8?q?[refactor]=20Input,=20List=EC=9D=98=20?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EA=B4=80=EB=A6=AC=EB=B6=80?= =?UTF-8?q?=EB=B6=84=EC=9D=84=20=EA=B4=80=EC=8B=AC=EC=82=AC=EB=B6=84?= =?UTF-8?q?=EB=A6=AC=20InputContainer,=20ListContainer=20=EB=A1=9C=20?= =?UTF-8?q?=EA=B4=80=EC=8B=AC=EC=82=AC=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/InputContainer.jsx | 25 +++++++++++++++++++++++++ src/ListContainer.jsx | 22 ++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 src/InputContainer.jsx create mode 100644 src/ListContainer.jsx diff --git a/src/InputContainer.jsx b/src/InputContainer.jsx new file mode 100644 index 000000000..80e3dd745 --- /dev/null +++ b/src/InputContainer.jsx @@ -0,0 +1,25 @@ +import { useDispatch, useSelector } from 'react-redux'; +import { addTask, updateTaskTitle } from './action'; + +import Input from './Input'; + +export default function InputContainer() { + const { taskTitle } = useSelector((state) => ({ + taskTitle: state.taskTitle, + })); + const dispatch = useDispatch(); + function handleChangeTaskTitle(event) { + dispatch(updateTaskTitle(event.target.value)); + } + function handleClickAdd() { + dispatch(addTask); + } + + return ( + + ); +} diff --git a/src/ListContainer.jsx b/src/ListContainer.jsx new file mode 100644 index 000000000..04a8e7395 --- /dev/null +++ b/src/ListContainer.jsx @@ -0,0 +1,22 @@ +import { useDispatch, useSelector } from 'react-redux'; +import { deleteTask } from './action'; + +import List from './List'; + +export default function ListContainer() { + const { tasks } = useSelector((state) => ({ + tasks: state.tasks, + })); + const dispatch = useDispatch(); + + function handleClickDelete(id) { + dispatch(deleteTask(id)); + } + + return ( + + ); +} From fe60def242de2bd816ec8ffebed749a9809d45f5 Mon Sep 17 00:00:00 2001 From: GUAJEGUICHAN Date: Wed, 22 Dec 2021 14:38:39 +0900 Subject: [PATCH 10/14] =?UTF-8?q?[refactor]=20Page=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=ED=95=98=EC=A7=80=20=EC=95=8A=EA=B3=A0=20=EB=A0=8C=EB=8D=94?= =?UTF-8?q?=ED=95=9C=EB=8B=A4.=20InputConatainer,=20ListContainer=EB=A1=9C?= =?UTF-8?q?=20=EB=A0=8C=EB=8D=94=ED=95=9C=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.jsx | 39 ++++++--------------------------------- 1 file changed, 6 insertions(+), 33 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index 2868d9181..75ec1e70f 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,38 +1,11 @@ -import { useDispatch, useSelector } from 'react-redux'; -import { addTask, deleteTask, updateTaskTitle } from './action'; +import InputContainer from './InputContainer'; +import ListContainer from './ListContainer'; -import Page from './Page'; - -function selector(state) { - return { - taskTitle: state.taskTitle, - tasks: state.tasks, - }; -} export default function App() { - // const [state, setState] = useState(initialState); - const { taskTitle, tasks } = useSelector(selector); - const dispatch = useDispatch(); - - function handleChangeTitle(event) { - dispatch(updateTaskTitle(event.target.value)); - } - - function handleClickAddTask() { - dispatch(addTask()); - } - - function handleClickDeleteTask(id) { - dispatch(deleteTask(id)); - } - return ( - + <> + + + ); } From 151408d858094e5395c2abb09a2d840f4e1918b1 Mon Sep 17 00:00:00 2001 From: GUAJEGUICHAN Date: Wed, 22 Dec 2021 15:42:26 +0900 Subject: [PATCH 11/14] =?UTF-8?q?[test]InputContainer,=20ListContainer=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/InputContainer.test.jsx | 36 ++++++++++++++++++++++++++++++++++++ src/ListContainer.test.jsx | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 src/InputContainer.test.jsx create mode 100644 src/ListContainer.test.jsx diff --git a/src/InputContainer.test.jsx b/src/InputContainer.test.jsx new file mode 100644 index 000000000..1c874cf0c --- /dev/null +++ b/src/InputContainer.test.jsx @@ -0,0 +1,36 @@ +// 테스트 할 것 +// taskTitle값이 있으면 화면에 그려진다. +// 추가 버튼이 있다. +// input입력하면 dispatch 작동한다. +// 추가 버튼 누르면 dispatch 작동한다. +// + +import { fireEvent, render } from '@testing-library/react'; +import { useDispatch, useSelector } from 'react-redux'; +import InputContainer from './InputContainer'; + +jest.mock('react-redux'); + +describe('InputContainer', () => { + // 더미 값을 주자 HOW? 지금 쓰고있는 useSelector를 가짜함수로 쓰면 됨! + const dispatch = jest.fn(); + useDispatch.mockImplementation(() => dispatch); + + useSelector.mockImplementation((selector) => selector({ + taskTitle: 'new Title', + })); + + it('redner InputContainer', () => { + const { getByText, getByDisplayValue } = render(); + expect(getByText('추가')).not.toBeNull(); + expect(getByDisplayValue('new Title')); + }); + + it('추가해서 dispatch 작동한다.', () => { + const { getByText } = render(); + fireEvent.click(getByText('추가')); + expect(dispatch).toBeCalledWith({ + type: 'addTask', + }); + }); +}); diff --git a/src/ListContainer.test.jsx b/src/ListContainer.test.jsx new file mode 100644 index 000000000..c2f85d0a5 --- /dev/null +++ b/src/ListContainer.test.jsx @@ -0,0 +1,36 @@ +import { fireEvent, render } from '@testing-library/react'; +import { useDispatch, useSelector } from 'react-redux'; +import ListContainer from './ListContainer'; + +jest.mock('react-redux'); + +describe('ListContainer', () => { + const dispatch = jest.fn(); + useDispatch.mockImplementation(() => dispatch); + const state = { + tasks: [{ + id: 100, + title: '숨 쉬기', + }], + }; + useSelector.mockImplementation((selector) => selector(state)); + + it('render Container', () => { + const { getByText } = render(); + + expect(getByText('완료')).not.toBeNull(); + expect(getByText('숨 쉬기')).not.toBeNull(); + }); + + it('완료 버튼이 작동한다.', () => { + const { getByText } = render(); + fireEvent.click(getByText('완료')); + + expect(dispatch).toBeCalledWith({ + type: 'deleteTask', + payload: { + id: 100, + }, + }); + }); +}); From 9bb934c32dfad5f9b91826064c3999f7f262ba3e Mon Sep 17 00:00:00 2001 From: GUAJEGUICHAN Date: Wed, 22 Dec 2021 15:42:49 +0900 Subject: [PATCH 12/14] =?UTF-8?q?[chore]=20=EC=98=A4=ED=83=80=20/=20eslint?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.test.jsx | 1 + src/InputContainer.jsx | 3 ++- src/action.js | 1 - 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/App.test.jsx b/src/App.test.jsx index e2bfcf6d4..8085c949f 100644 --- a/src/App.test.jsx +++ b/src/App.test.jsx @@ -19,6 +19,7 @@ test('App', () => { )); expect(getByText(/추가/)).not.toBeNull(); + expect(getByText(/숨 쉬기/)).not.toBeNull(); // TODO: 통합 테스트 코드 작성 // CodeceptJS => 실제 브라우저에서 사용자 테스트 실행 가능. diff --git a/src/InputContainer.jsx b/src/InputContainer.jsx index 80e3dd745..986349f2d 100644 --- a/src/InputContainer.jsx +++ b/src/InputContainer.jsx @@ -8,11 +8,12 @@ export default function InputContainer() { taskTitle: state.taskTitle, })); const dispatch = useDispatch(); + function handleChangeTaskTitle(event) { dispatch(updateTaskTitle(event.target.value)); } function handleClickAdd() { - dispatch(addTask); + dispatch(addTask()); } return ( diff --git a/src/action.js b/src/action.js index 27c253c25..8ce8ab2d4 100644 --- a/src/action.js +++ b/src/action.js @@ -10,7 +10,6 @@ export function updateTaskTitle(taskTitle) { export function addTask() { return { type: 'addTask', - }; } From ae7c9fd7a534daa93ce3b01742506e0bdb98a33d Mon Sep 17 00:00:00 2001 From: GUAJEGUICHAN Date: Wed, 22 Dec 2021 17:10:36 +0900 Subject: [PATCH 13/14] =?UTF-8?q?[test]=20reducer.=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/reducer.js | 4 ++- src/reducer.test.js | 80 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 src/reducer.test.js diff --git a/src/reducer.js b/src/reducer.js index 7a5758c1a..7a4a4e306 100644 --- a/src/reducer.js +++ b/src/reducer.js @@ -13,7 +13,9 @@ export default function reducer(state = initialState, action) { } if (action.type === 'addTask') { const { newId, taskTitle, tasks } = state; - + if (taskTitle === '') { + return state; + } return { ...state, newId: newId + 1, diff --git a/src/reducer.test.js b/src/reducer.test.js new file mode 100644 index 000000000..5b45a063c --- /dev/null +++ b/src/reducer.test.js @@ -0,0 +1,80 @@ +// updateTaskTitle +// addTask +// deleteTask +// 가 작동하는가? +// 특히 +// addTask는 TaskTitle===''일 떄 작동하지 않는다. +// deleteTask는 wrongId일떄 작동하지 않는다. + +import { addTask, deleteTask, updateTaskTitle } from './action'; +import reducer from './reducer'; + +describe('reducer', () => { + it('updateTaskTitle', () => { + const state = { + newId: 100, + taskTitle: '', + tasks: [], + }; + const newState = reducer(state, updateTaskTitle('new TaskTitle')); + + expect(newState.taskTitle).toBe('new TaskTitle'); + }); +}); +describe('addTask', () => { + context('taskTtle이 있을 때', () => { + it('작동 한다.', () => { + const state = { + newId: 100, + taskTitle: 'new TaskTitle', + tasks: [], + }; + const newState = reducer(state, addTask()); + expect(newState.tasks).toHaveLength(1); + }); + }); + context('taskTitle이 없을 때', () => { + it('작동 안한다.', () => { + const state = { + newId: 100, + taskTitle: '', + tasks: [], + }; + const newState = reducer(state, addTask()); + expect(newState.tasks).toHaveLength(0); + }); + }); +}); + +describe('deleteTask', () => { + context('wrongId일때', () => { + it('작동안한다.', () => { + const state = { + newId: 100, + taskTitle: '', + tasks: [ + { + id: 100, + title: '독서', + }], + }; + const newState = reducer(state, deleteTask(200)); + expect(newState.tasks).toHaveLength(1); + }); + }); + context('rigthId일때', () => { + it('작동한다.', () => { + const state = { + newId: 100, + taskTitle: '', + tasks: [ + { + id: 100, + title: '독서', + }], + }; + const newState = reducer(state, deleteTask(100)); + expect(newState.tasks).toHaveLength(0); + }); + }); +}); From 8ea32fa99f3e3a28968ab404b9857d37b478800e Mon Sep 17 00:00:00 2001 From: GUAJEGUICHAN Date: Wed, 22 Dec 2021 17:12:06 +0900 Subject: [PATCH 14/14] =?UTF-8?q?[refactor]=20=EC=A4=91=EB=B3=B5=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0=EB=A5=BC=20=EC=9C=84=ED=95=9C=20=ED=95=A8=EC=88=98=20?= =?UTF-8?q?=EC=9D=B4=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 다음 함수들을 구현 reduceUpdateTaskTitle reduceAddTask reduceDeleteTask --- src/reducer.test.js | 101 ++++++++++++++++++++++---------------------- 1 file changed, 50 insertions(+), 51 deletions(-) diff --git a/src/reducer.test.js b/src/reducer.test.js index 5b45a063c..a6339bd4b 100644 --- a/src/reducer.test.js +++ b/src/reducer.test.js @@ -1,69 +1,52 @@ -// updateTaskTitle -// addTask -// deleteTask -// 가 작동하는가? -// 특히 -// addTask는 TaskTitle===''일 떄 작동하지 않는다. -// deleteTask는 wrongId일떄 작동하지 않는다. - import { addTask, deleteTask, updateTaskTitle } from './action'; import reducer from './reducer'; describe('reducer', () => { - it('updateTaskTitle', () => { - const state = { - newId: 100, - taskTitle: '', - tasks: [], - }; - const newState = reducer(state, updateTaskTitle('new TaskTitle')); - - expect(newState.taskTitle).toBe('new TaskTitle'); - }); -}); -describe('addTask', () => { - context('taskTtle이 있을 때', () => { - it('작동 한다.', () => { + describe('updateTaskTitle', () => { + function reduceUpdateTaskTitle(taskTitle) { const state = { newId: 100, - taskTitle: 'new TaskTitle', + taskTitle: '', tasks: [], }; - const newState = reducer(state, addTask()); - expect(newState.tasks).toHaveLength(1); - }); + + return reducer(state, updateTaskTitle(taskTitle)); + } + + const newState = reduceUpdateTaskTitle('new TaskTitle'); + expect(newState.taskTitle).toBe('new TaskTitle'); }); - context('taskTitle이 없을 때', () => { - it('작동 안한다.', () => { + + describe('addTask', () => { + function reduceAddTask(taskTitle) { const state = { newId: 100, - taskTitle: '', + taskTitle, tasks: [], }; - const newState = reducer(state, addTask()); - expect(newState.tasks).toHaveLength(0); + + return reducer(state, addTask()); + } + + context('taskTtle이 있을 때', () => { + it('작동 한다.', () => { + const newState = reduceAddTask('new TaskTitle'); + + expect(newState.tasks).toHaveLength(1); + }); }); - }); -}); -describe('deleteTask', () => { - context('wrongId일때', () => { - it('작동안한다.', () => { - const state = { - newId: 100, - taskTitle: '', - tasks: [ - { - id: 100, - title: '독서', - }], - }; - const newState = reducer(state, deleteTask(200)); - expect(newState.tasks).toHaveLength(1); + context('taskTitle이 없을 때', () => { + it('작동 안한다.', () => { + const newState = reduceAddTask(''); + + expect(newState.tasks).toHaveLength(0); + }); }); }); - context('rigthId일때', () => { - it('작동한다.', () => { + + describe('deleteTask', () => { + function reduceDeleteTask(id) { const state = { newId: 100, taskTitle: '', @@ -73,8 +56,24 @@ describe('deleteTask', () => { title: '독서', }], }; - const newState = reducer(state, deleteTask(100)); - expect(newState.tasks).toHaveLength(0); + + return reducer(state, deleteTask(id)); + } + + context('wrongId일때', () => { + it('작동안한다.', () => { + const newState = reduceDeleteTask(200); + + expect(newState.tasks).toHaveLength(1); + }); + }); + + context('rigthId일때', () => { + it('작동한다.', () => { + const newState = reduceDeleteTask(100); + + expect(newState.tasks).toHaveLength(0); + }); }); }); });