瀏覽代碼

first commit

Евгения Акиншина 3 年之前
當前提交
bc0d3adca3

+ 23 - 0
.gitignore

@@ -0,0 +1,23 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+/node_modules
+/.pnp
+.pnp.js
+
+# testing
+/coverage
+
+# production
+/build
+
+# misc
+.DS_Store
+.env.local
+.env.development.local
+.env.test.local
+.env.production.local
+
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*

+ 1 - 0
README.md

@@ -0,0 +1 @@
+# Redux Typescript Counter

File diff suppressed because it is too large
+ 17358 - 0
package-lock.json


+ 52 - 0
package.json

@@ -0,0 +1,52 @@
+{
+  "name": "increment",
+  "version": "0.1.0",
+  "private": true,
+  "dependencies": {
+    "@testing-library/jest-dom": "^5.11.9",
+    "@testing-library/react": "^11.2.5",
+    "@testing-library/user-event": "^12.6.3",
+    "@types/jest": "^26.0.20",
+    "@types/node": "^12.19.16",
+    "@types/react": "^17.0.1",
+    "@types/react-dom": "^17.0.0",
+    "@types/react-redux": "^7.1.16",
+    "@types/react-router-dom": "^5.1.7",
+    "axios": "^0.21.1",
+    "node-sass": "^4.14.1",
+    "react": "^17.0.1",
+    "react-dom": "^17.0.1",
+    "react-redux": "^7.2.2",
+    "react-router-dom": "^5.2.0",
+    "react-scripts": "4.0.2",
+    "redux": "^4.0.5",
+    "redux-devtools-extension": "^2.13.8",
+    "redux-thunk": "^2.3.0",
+    "typescript": "^4.1.4",
+    "web-vitals": "^1.1.0"
+  },
+  "scripts": {
+    "start": "react-scripts start",
+    "build": "react-scripts build",
+    "test": "react-scripts test",
+    "eject": "react-scripts eject"
+  },
+  "eslintConfig": {
+    "extends": [
+      "react-app",
+      "react-app/jest"
+    ]
+  },
+  "browserslist": {
+    "production": [
+      ">0.2%",
+      "not dead",
+      "not op_mini all"
+    ],
+    "development": [
+      "last 1 chrome version",
+      "last 1 firefox version",
+      "last 1 safari version"
+    ]
+  }
+}

二進制
public/favicon.ico


+ 43 - 0
public/index.html

@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="utf-8" />
+    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
+    <meta name="viewport" content="width=device-width, initial-scale=1" />
+    <meta name="theme-color" content="#000000" />
+    <meta
+      name="description"
+      content="Web site created using create-react-app"
+    />
+    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
+    <!--
+      manifest.json provides metadata used when your web app is installed on a
+      user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
+    -->
+    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
+    <!--
+      Notice the use of %PUBLIC_URL% in the tags above.
+      It will be replaced with the URL of the `public` folder during the build.
+      Only files inside the `public` folder can be referenced from the HTML.
+
+      Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
+      work correctly both with client-side routing and a non-root public URL.
+      Learn how to configure a non-root public URL by running `npm run build`.
+    -->
+    <title>React App</title>
+  </head>
+  <body>
+    <noscript>You need to enable JavaScript to run this app.</noscript>
+    <div id="root"></div>
+    <!--
+      This HTML file is a template.
+      If you open it directly in the browser, you will see an empty page.
+
+      You can add webfonts, meta tags, or analytics to this file.
+      The build step will place the bundled scripts into the <body> tag.
+
+      To begin the development, run `npm start` or `yarn start`.
+      To create a production bundle, use `npm run build` or `yarn build`.
+    -->
+  </body>
+</html>

二進制
public/logo192.png


二進制
public/logo512.png


+ 25 - 0
public/manifest.json

@@ -0,0 +1,25 @@
+{
+  "short_name": "React App",
+  "name": "Create React App Sample",
+  "icons": [
+    {
+      "src": "favicon.ico",
+      "sizes": "64x64 32x32 24x24 16x16",
+      "type": "image/x-icon"
+    },
+    {
+      "src": "logo192.png",
+      "type": "image/png",
+      "sizes": "192x192"
+    },
+    {
+      "src": "logo512.png",
+      "type": "image/png",
+      "sizes": "512x512"
+    }
+  ],
+  "start_url": ".",
+  "display": "standalone",
+  "theme_color": "#000000",
+  "background_color": "#ffffff"
+}

+ 3 - 0
public/robots.txt

@@ -0,0 +1,3 @@
+# https://www.robotstxt.org/robotstxt.html
+User-agent: *
+Disallow:

+ 15 - 0
src/components/App.tsx

@@ -0,0 +1,15 @@
+import React from 'react'
+import "../index.sass";
+import {Provider} from 'react-redux'
+import store from '../state/store'
+import Count from './Count';
+
+const App = () => {
+  return (
+    <Provider store={store}>
+        <Count />
+    </Provider>
+  )
+}
+
+export default App;

+ 27 - 0
src/components/Count.tsx

@@ -0,0 +1,27 @@
+import React, {Fragment} from 'react';
+import {useDispatch} from 'react-redux';
+import {ActionType} from '../state/action-types';
+import ShowResult from './ShowResult';
+
+
+const Count:React.FC  = () => {
+
+    const dispatch = useDispatch();
+
+    const handleClick = (e: React.MouseEvent) => {
+        const target = (e.target as HTMLButtonElement).getAttribute('value');
+        dispatch({type: target})
+    }
+
+    return (
+        <>
+            <ShowResult />
+            <Fragment>
+            <button className='btn_click' value={ActionType.INCREMENT} onClick={(e) => handleClick(e)}>Increment</button>
+            <button className='btn_click' value={ActionType.DECREMENT} onClick={(e) => handleClick(e)}>Decrement</button>
+            </Fragment>
+        </>
+    )
+}
+
+export default Count;

+ 14 - 0
src/components/ShowResult.tsx

@@ -0,0 +1,14 @@
+import React, {Fragment} from 'react'
+import {useTypedSelector} from '../hooks/useTypedSelector';
+
+const ShowResult:React.FC = () => {
+    const {sum} = useTypedSelector((state:any) => state.count);
+ 
+    return (
+        <Fragment>
+            <h2> Counter: {sum}</h2>
+        </Fragment>
+    )
+}
+
+export default ShowResult;

+ 4 - 0
src/hooks/useTypedSelector.ts

@@ -0,0 +1,4 @@
+import { useSelector, TypedUseSelectorHook } from "react-redux";
+import { RootState } from "../state/reducers";
+
+export const useTypedSelector: TypedUseSelectorHook<RootState> = useSelector;

+ 58 - 0
src/index.sass

@@ -0,0 +1,58 @@
+body
+    margin: 0
+    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
+    'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
+    sans-serif
+    -webkit-font-smoothing: antialiased
+    -moz-osx-font-smoothing: grayscale
+
+code 
+    font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace
+
+$slyles: Verdana, Geneva, Tahoma, sans-serif
+$colors: blue
+
+h2 
+    font-family: $slyles
+    color: $colors
+    margin-left: 5px
+
+.btn_click
+    position: relative
+    display: inline-block
+    cursor: pointer
+    margin-left: 2px
+    width: 6em
+    height: 2.5em
+    line-height: 2.4em
+    vertical-align: middle
+    text-align: center
+    text-decoration: none
+    user-select: none
+    color: #000
+    outline: none
+    border: 1px solid rgba(110,121,128,.8)
+    border-top-color: rgba(0,0,0,.3)
+    border-radius: 5px
+    background: rgb(206, 220, 231) linear-gradient(rgb(206,220,231), rgb(89,106,114))
+    box-shadow:
+    0 -1px rgba(10,21,28,.9) inset,
+    0 1px rgba(255,255,255,.5) inset
+    &:hover 
+        background: linear-gradient(#d2dfea, #71828c)
+    &active 
+        line-height: 2.6em
+        background: linear-gradient(#bac6cf, #c5d3de 20%, #71828c)
+        box-shadow: 0 -1px rgba(255,255,255,.4) inset
+    &:before
+        position: absolute
+        top: -10px 
+        right: -10px
+        bottom: -10px
+        left: -10px
+        z-index: -1
+        border-radius: 8px
+        background: linear-gradient(rgba(200,200,200,.5), rgba(240,240,240,.5))
+
+.counter_text 
+    margin-left: 80px

+ 12 - 0
src/index.tsx

@@ -0,0 +1,12 @@
+import React from 'react';
+import ReactDOM from 'react-dom';
+import App from './components/App';
+
+
+ReactDOM.render(
+  <React.StrictMode>
+    <App />
+  </React.StrictMode>,
+  document.getElementById('root')
+);
+

+ 1 - 0
src/react-app-env.d.ts

@@ -0,0 +1 @@
+/// <reference types="react-scripts" />

+ 19 - 0
src/state/action-creators/index.ts

@@ -0,0 +1,19 @@
+import { ActionType } from "../action-types";
+import { Dispatch } from "redux";
+import { Action } from "../actions";
+
+// Two different approaches
+
+const increment = () => {
+  return (dispatch: Dispatch<Action>) => {
+    dispatch({
+      type: ActionType.INCREMENT,
+    });
+  };
+};
+
+const decrement = () => {
+  return {
+    type: ActionType.DECREMENT,
+  };
+};

+ 4 - 0
src/state/action-types/index.ts

@@ -0,0 +1,4 @@
+export enum ActionType {
+  INCREMENT = "INCREMENT",
+  DECREMENT = "DECREMENT",
+}

+ 4 - 0
src/state/actions/index.ts

@@ -0,0 +1,4 @@
+export interface Action {
+  type: string;
+  payload?: any;
+}

+ 2 - 0
src/state/index.ts

@@ -0,0 +1,2 @@
+export * from "./store";
+export * as actionCreators from "./action-creators";

+ 23 - 0
src/state/reducers/countReducers.ts

@@ -0,0 +1,23 @@
+import { ActionType } from "../action-types";
+import { Action } from "../actions";
+
+interface appState {
+  sum: number;
+}
+
+const initialState = {
+  sum: 0,
+};
+
+const reducer = (state: appState = initialState, action: Action): appState => {
+  switch (action.type) {
+    case ActionType.INCREMENT:
+      return { sum: state.sum + 1 };
+    case ActionType.DECREMENT:
+      return { sum: state.sum - 1 };
+    default:
+      return state;
+  }
+};
+
+export default reducer;

+ 10 - 0
src/state/reducers/index.ts

@@ -0,0 +1,10 @@
+import { combineReducers } from "redux";
+import countReducers from "./countReducers";
+
+const reducers = combineReducers({
+  count: countReducers,
+});
+
+export default reducers;
+
+export type RootState = ReturnType<typeof reducers>;

+ 16 - 0
src/state/store.ts

@@ -0,0 +1,16 @@
+import { createStore, applyMiddleware } from "redux";
+import { composeWithDevTools } from "redux-devtools-extension";
+import thunk from "redux-thunk";
+import reducers from "./reducers";
+
+const initialState = {};
+
+const middleWare = [thunk];
+
+const store = createStore(
+  reducers,
+  initialState,
+  composeWithDevTools(applyMiddleware(...middleWare))
+);
+
+export default store;

+ 26 - 0
tsconfig.json

@@ -0,0 +1,26 @@
+{
+  "compilerOptions": {
+    "target": "es5",
+    "lib": [
+      "dom",
+      "dom.iterable",
+      "esnext"
+    ],
+    "allowJs": true,
+    "skipLibCheck": true,
+    "esModuleInterop": true,
+    "allowSyntheticDefaultImports": true,
+    "strict": true,
+    "forceConsistentCasingInFileNames": true,
+    "noFallthroughCasesInSwitch": true,
+    "module": "esnext",
+    "moduleResolution": "node",
+    "resolveJsonModule": true,
+    "isolatedModules": true,
+    "noEmit": true,
+    "jsx": "react-jsx"
+  },
+  "include": [
+    "src"
+  ]
+}