From 7f2201ac0453f31673f19b59104b83eb2965f24e Mon Sep 17 00:00:00 2001 From: Dan Antal Date: Tue, 12 Mar 2019 01:08:54 +0200 Subject: [PATCH] Add react, react-redux and extract logic of the calculator to components --- package.json | 6 +++ src/Button.tsx | 17 +++++++ src/Display.tsx | 22 +++++++++ src/Input.tsx | 33 +++++++++++++ src/index.html | 21 -------- src/index.ts | 69 -------------------------- src/index.tsx | 30 ++++++++++++ src/store.ts | 41 ++++++++++++++++ tsconfig.json | 7 +-- webpack.config.js | 2 +- yarn.lock | 122 ++++++++++++++++++++++++++++++++++++++++++++-- 11 files changed, 272 insertions(+), 98 deletions(-) create mode 100644 src/Button.tsx create mode 100644 src/Display.tsx create mode 100644 src/Input.tsx delete mode 100644 src/index.ts create mode 100644 src/index.tsx create mode 100644 src/store.ts diff --git a/package.json b/package.json index d0f45ae..3c7fe7c 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,9 @@ "start": "webpack-dev-server --open" }, "devDependencies": { + "@types/react": "^16.8.7", + "@types/react-dom": "^16.8.2", + "@types/react-redux": "^7.0.3", "babel-cli": "6.26.0", "babel-preset-env": "1.6.0", "clean-webpack-plugin": "^2.0.0", @@ -24,6 +27,9 @@ }, "dependencies": { "@types/redux": "^3.6.0", + "react": "^16.8.4", + "react-dom": "^16.8.4", + "react-redux": "^6.0.1", "redux": "^4.0.1" } } diff --git a/src/Button.tsx b/src/Button.tsx new file mode 100644 index 0000000..2d50b1b --- /dev/null +++ b/src/Button.tsx @@ -0,0 +1,17 @@ +import React, { Component } from 'react' + +interface ButtonProps { + onClick: () => void; + title: string; +} + +export default class Button extends Component { + render() { + const {onClick, title} = this.props; + return ( + + ); + } +} diff --git a/src/Display.tsx b/src/Display.tsx new file mode 100644 index 0000000..2c0b93c --- /dev/null +++ b/src/Display.tsx @@ -0,0 +1,22 @@ +import React, { Component } from 'react' +import { connect } from 'react-redux' + +interface DisplayProps { + value: number; +} + +export class Display extends Component { + render() { + return ( +
+ {this.props.value} +
+ ) + } +} + +const mapStateToProps = (state: any) => ({ + value: state.total +}); + +export default connect(mapStateToProps, null)(Display) diff --git a/src/Input.tsx b/src/Input.tsx new file mode 100644 index 0000000..5116924 --- /dev/null +++ b/src/Input.tsx @@ -0,0 +1,33 @@ +import React, { Component } from 'react' +import { connect } from 'react-redux' +import { setCurrent } from './store' + +interface InputProps { + value: number + setCurrent: (value: number) => void; +} + +export class Input extends Component { + + onChange = (e: React.FormEvent) => { + this.props.setCurrent(parseInt(e.currentTarget.value)); + } + + render() { + const {value} = this.props; + + return ( + + ) + } +} + +const mapStateToProps = (state: any) => ({ + value: state.inputValue +}) + +const mapDispatchToProps = dispatch => ({ + setCurrent: (value: number) => dispatch(setCurrent(value)) +}); + +export default connect(mapStateToProps, mapDispatchToProps)(Input) diff --git a/src/index.html b/src/index.html index c1a3936..cffe146 100644 --- a/src/index.html +++ b/src/index.html @@ -9,27 +9,6 @@
-
-
-
- -
- -
- - - - - -
-
- -
- -
-

0

-
-
\ No newline at end of file diff --git a/src/index.ts b/src/index.ts deleted file mode 100644 index 6936e2d..0000000 --- a/src/index.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { createStore } from 'redux'; - -// SET-UP -const reducer = (state = {total: 0}, action: {type: string, payload?: any}) => { - console.log(action); - - switch(action.type) { - case 'ADD': - return {...state, total: state.total + action.payload.value}; - case 'SUBTRACT': - return {...state, total: state.total - action.payload.value}; - case 'RESET': - return {...state, total: 0}; - default: - return state; - } -}; - -const enhancer = ((window as any).__REDUX_DEVTOOLS_EXTENSION__ && (window as any).__REDUX_DEVTOOLS_EXTENSION__()) - -const store = createStore(reducer, enhancer); - -// ACTION-CREATORS -const add = (value: number) => ({ - type: 'ADD', - payload: { value }, -}); - -const subtract = (value: number) => ({ - type: 'SUBTRACT', - payload: { value }, -}); - -const reset = () => ({ type: 'RESET' }); - -// SUBSCRIBE -store.subscribe(() => { - setTotal(store.getState().total); -}); - -// DISPATCH -document.getElementById('add-btn').addEventListener('click', () => { - store.dispatch(add(getValue())); -}); - -document.getElementById('subtract-btn').addEventListener('click', () => { - store.dispatch(subtract(getValue())); -}); - -document.getElementById('reset-btn').addEventListener('click', () => { - store.dispatch(reset()); -}); - - -// HELPERS - - -/*/************************ - PART 2: UTILITY METHODS -/**************************/ - -const getValue = () => { - const value = parseInt((document.getElementById('op-number') as HTMLInputElement).value); - return isNaN(value) ? 0 : value; -}; - -const setTotal = (value: number) => { - document.getElementById('grand-total').innerHTML = value.toString(); -}; diff --git a/src/index.tsx b/src/index.tsx new file mode 100644 index 0000000..6a67f69 --- /dev/null +++ b/src/index.tsx @@ -0,0 +1,30 @@ +import * as React from "react"; +import * as ReactDOM from "react-dom" +import { Provider } from 'react-redux' + +import Button from "./Button"; +import Input from "./Input"; +import Display from "./Display"; + +import { add, subtract, reset, store } from './store' + +class App extends React.Component<{}, {}> { + render() { + return ( + +
+ +
+
+ ); + } +} + +ReactDOM.render( + , + document.getElementById("app") +); \ No newline at end of file diff --git a/src/store.ts b/src/store.ts new file mode 100644 index 0000000..290643d --- /dev/null +++ b/src/store.ts @@ -0,0 +1,41 @@ +import { createStore } from 'redux'; + +// SET-UP +const reducer = (state = {total: 0, current: 0}, action: {type: string, payload?: any}) => { + console.log(action); + + switch(action.type) { + case 'SET_CURRENT': + return {...state, current: action.payload.value}; + case 'ADD': + return {...state, total: state.total + action.payload.value}; + case 'SUBTRACT': + return {...state, total: state.total - action.payload.value}; + case 'RESET': + return {...state, total: 0}; + default: + return state; + } +}; + +const enhancer = ((window as any).__REDUX_DEVTOOLS_EXTENSION__ && (window as any).__REDUX_DEVTOOLS_EXTENSION__()) + +// ACTION-CREATORS +export const add = (value: number) => ({ + type: 'ADD', + payload: { value }, +}); + +export const subtract = (value: number) => ({ + type: 'SUBTRACT', + payload: { value }, +}); + +export const setCurrent = (value: number) => ({ + type: 'SET_CURRENT', + payload: { value }, + }); + +export const reset = () => ({ type: 'RESET' }); + +export const store = createStore(reducer, enhancer); \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 754c85f..0e43ba7 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,10 +2,11 @@ "compilerOptions": { "outDir": "./dist/", "sourceMap": true, - "noImplicitAny": true, - "module": "commonjs", + "noImplicitAny": false, + "module": "es2015", "target": "es5", "jsx": "react", - "allowJs": true + "allowJs": true, + "allowSyntheticDefaultImports": true } } \ No newline at end of file diff --git a/webpack.config.js b/webpack.config.js index ab9f379..3e4b819 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -3,7 +3,7 @@ const HtmlWebpackPlugin = require("html-webpack-plugin"); const CleanWebpackPlugin = require("clean-webpack-plugin"); module.exports = { - entry: "./src/index.ts", + entry: "./src/index.tsx", module: { rules: [ { diff --git a/yarn.lock b/yarn.lock index e2f1dd4..a93e1ac 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,49 @@ # yarn lockfile v1 +"@babel/runtime@^7.3.1": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.3.4.tgz#73d12ba819e365fcf7fd152aed56d6df97d21c83" + integrity sha512-IvfvnMdSaLBateu0jfsYIpZTxAc2cKEXEMiezGGN75QcBcecDUKd3PgLAncT0oOgxKy8dd8hrJKj9MfzgfZd6g== + dependencies: + regenerator-runtime "^0.12.0" + +"@types/hoist-non-react-statics@*": + version "3.3.0" + resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz#a59c0c995cc885bef1b8ec2241b114f9b35b517b" + integrity sha512-O2OGyW9wlO2bbDmZRH17MecArQfsIa1g//ve2IJk6BnmwEglFz5kdhP1BlgeqjVNH5IHIhsc83DWFo8StCe8+Q== + dependencies: + "@types/react" "*" + +"@types/prop-types@*": + version "15.7.0" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.0.tgz#4c48fed958d6dcf9487195a0ef6456d5f6e0163a" + integrity sha512-eItQyV43bj4rR3JPV0Skpl1SncRCdziTEK9/v8VwXmV6d/qOUO8/EuWeHBbCZcsfSHfzI5UyMJLCSXtxxznyZg== + +"@types/react-dom@^16.8.2": + version "16.8.2" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.8.2.tgz#9bd7d33f908b243ff0692846ef36c81d4941ad12" + integrity sha512-MX7n1wq3G/De15RGAAqnmidzhr2Y9O/ClxPxyqaNg96pGyeXUYPSvujgzEVpLo9oIP4Wn1UETl+rxTN02KEpBw== + dependencies: + "@types/react" "*" + +"@types/react-redux@^7.0.3": + version "7.0.3" + resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.0.3.tgz#b8dc3faa954b7f28e4b0209bcf9209b45251ed6b" + integrity sha512-6qsIHHNwF41viooUgR2lXHL81v3uyeJsugq9YCMYE4g2bDyG710G/I/w5nbn7AQ9XfuOLUwrWfm3edV7gDJ9AQ== + dependencies: + "@types/hoist-non-react-statics" "*" + "@types/react" "*" + redux "^4.0.0" + +"@types/react@*", "@types/react@^16.8.7": + version "16.8.7" + resolved "https://registry.yarnpkg.com/@types/react/-/react-16.8.7.tgz#7b1c0223dd5494f9b4501ad2a69aa6acb350a29b" + integrity sha512-0xbkIyrDNKUn4IJVf8JaCn+ucao/cq6ZB8O6kSzhrJub1cVSqgTArtG0qCfdERWKMEIvUbrwLXeQMqWEsyr9dA== + dependencies: + "@types/prop-types" "*" + csstype "^2.2.0" + "@types/redux@^3.6.0": version "3.6.0" resolved "https://registry.yarnpkg.com/@types/redux/-/redux-3.6.0.tgz#f1ebe1e5411518072e4fdfca5c76e16e74c1399a" @@ -1728,6 +1771,11 @@ csso@~2.3.1: clap "^1.0.9" source-map "^0.5.3" +csstype@^2.2.0: + version "2.6.3" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.3.tgz#b701e5968245bf9b08d54ac83d00b624e622a9fa" + integrity sha512-rINUZXOkcBmoHWEyu7JdHu5JMzkGRoMX4ov9830WNgxf5UYxcBUO0QTKAqeJ5EZfSdlrcJYkC8WwfVW7JYi4yg== + cyclist@~0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640" @@ -2670,6 +2718,13 @@ hmac-drbg@^1.0.0: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" +hoist-non-react-statics@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz#b09178f0122184fb95acf525daaecb4d8f45958b" + integrity sha512-0XsbTXxgiaCDYDIWFcwkmerZPSwywfUqYmwT4jzewKTQSWoE6FCMoUVOeBJWK3E/CrWbxRG3m5GzY4lnIwGRBA== + dependencies: + react-is "^16.7.0" + home-or-tmp@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" @@ -2889,7 +2944,7 @@ interpret@^1.1.0: resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296" integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw== -invariant@^2.2.2: +invariant@^2.2.2, invariant@^2.2.4: version "2.2.4" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== @@ -3356,7 +3411,7 @@ loglevel@^1.4.1: resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.1.tgz#e0fc95133b6ef276cdc8887cdaf24aa6f156f8fa" integrity sha1-4PyVEztu8nbNyIh82vJKpvFW+Po= -loose-envify@^1.0.0, loose-envify@^1.4.0: +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== @@ -3823,7 +3878,7 @@ number-is-nan@^1.0.0: resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= -object-assign@^4.0.1, object-assign@^4.1.0: +object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= @@ -4464,6 +4519,15 @@ promise-inflight@^1.0.1: resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= +prop-types@^15.6.2, prop-types@^15.7.2: + version "15.7.2" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" + integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.8.1" + proxy-addr@~2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.4.tgz#ecfc733bf22ff8c6f407fa275327b9ab67e48b93" @@ -4611,6 +4675,43 @@ rc@^1.2.7: minimist "^1.2.0" strip-json-comments "~2.0.1" +react-dom@^16.8.4: + version "16.8.4" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.8.4.tgz#1061a8e01a2b3b0c8160037441c3bf00a0e3bc48" + integrity sha512-Ob2wK7XG2tUDt7ps7LtLzGYYB6DXMCLj0G5fO6WeEICtT4/HdpOi7W/xLzZnR6RCG1tYza60nMdqtxzA8FaPJQ== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + prop-types "^15.6.2" + scheduler "^0.13.4" + +react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.2: + version "16.8.4" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.4.tgz#90f336a68c3a29a096a3d648ab80e87ec61482a2" + integrity sha512-PVadd+WaUDOAciICm/J1waJaSvgq+4rHE/K70j0PFqKhkTBsPv/82UGQJNXAngz1fOQLLxI6z1sEDmJDQhCTAA== + +react-redux@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-6.0.1.tgz#0d423e2c1cb10ada87293d47e7de7c329623ba4d" + integrity sha512-T52I52Kxhbqy/6TEfBv85rQSDz6+Y28V/pf52vDWs1YRXG19mcFOGfHnY2HsNFHyhP+ST34Aih98fvt6tqwVcQ== + dependencies: + "@babel/runtime" "^7.3.1" + hoist-non-react-statics "^3.3.0" + invariant "^2.2.4" + loose-envify "^1.4.0" + prop-types "^15.7.2" + react-is "^16.8.2" + +react@^16.8.4: + version "16.8.4" + resolved "https://registry.yarnpkg.com/react/-/react-16.8.4.tgz#fdf7bd9ae53f03a9c4cd1a371432c206be1c4768" + integrity sha512-0GQ6gFXfUH7aZcjGVymlPOASTuSjlQL4ZtVC5YKH+3JL6bBLCVO21DknzmaPlI90LN253ojj02nsapy+j7wIjg== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + prop-types "^15.6.2" + scheduler "^0.13.4" + "readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6: version "2.3.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" @@ -4658,7 +4759,7 @@ reduce-function-call@^1.0.1: dependencies: balanced-match "^0.4.2" -redux@*, redux@^4.0.1: +redux@*, redux@^4.0.0, redux@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/redux/-/redux-4.0.1.tgz#436cae6cc40fbe4727689d7c8fae44808f1bfef5" integrity sha512-R7bAtSkk7nY6O/OYMVR9RiBI+XghjF9rlbl5806HJbQph0LJVHZrU5oaO4q70eUKiqMRqm4y07KLTlMZ2BlVmg== @@ -4681,6 +4782,11 @@ regenerator-runtime@^0.11.0: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== +regenerator-runtime@^0.12.0: + version "0.12.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de" + integrity sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg== + regenerator-transform@^0.10.0: version "0.10.1" resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" @@ -4862,6 +4968,14 @@ sax@^1.2.4, sax@~1.2.1: resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== +scheduler@^0.13.4: + version "0.13.4" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.13.4.tgz#8fef05e7a3580c76c0364d2df5e550e4c9140298" + integrity sha512-cvSOlRPxOHs5dAhP9yiS/6IDmVAVxmk33f0CtTJRkmUWcb1Us+t7b1wqdzoC0REw2muC9V5f1L/w5R5uKGaepA== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + schema-utils@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.3.0.tgz#f5877222ce3e931edae039f17eb3716e7137f8cf"