11 changed files with 15532 additions and 0 deletions
@ -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* |
||||
@ -0,0 +1,35 @@
|
||||
{ |
||||
"name": "enhanced-reducer", |
||||
"version": "0.1.0", |
||||
"private": true, |
||||
"dependencies": { |
||||
"@testing-library/jest-dom": "^4.2.4", |
||||
"@testing-library/react": "^9.5.0", |
||||
"@testing-library/user-event": "^7.2.1", |
||||
"react": "^16.13.1", |
||||
"react-dom": "^16.13.1", |
||||
"react-scripts": "3.4.1", |
||||
"bootstrap": "4.4.1" |
||||
}, |
||||
"scripts": { |
||||
"start": "react-scripts start", |
||||
"build": "react-scripts build", |
||||
"test": "react-scripts test", |
||||
"eject": "react-scripts eject" |
||||
}, |
||||
"eslintConfig": { |
||||
"extends": "react-app" |
||||
}, |
||||
"browserslist": { |
||||
"production": [ |
||||
">0.2%", |
||||
"not dead", |
||||
"not op_mini all" |
||||
], |
||||
"development": [ |
||||
"last 1 chrome version", |
||||
"last 1 firefox version", |
||||
"last 1 safari version" |
||||
] |
||||
} |
||||
} |
||||
|
After Width: | Height: | Size: 3.1 KiB |
@ -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> |
||||
|
After Width: | Height: | Size: 5.2 KiB |
|
After Width: | Height: | Size: 9.4 KiB |
@ -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" |
||||
} |
||||
@ -0,0 +1,3 @@
|
||||
# https://www.robotstxt.org/robotstxt.html |
||||
User-agent: * |
||||
Disallow: |
||||
@ -0,0 +1,13 @@
|
||||
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; |
||||
} |
||||
@ -0,0 +1,141 @@
|
||||
import * as React from "react"; |
||||
import { render } from "react-dom"; |
||||
import produce from "immer"; |
||||
import { set, has } from "lodash"; |
||||
import "bootstrap/dist/css/bootstrap.css"; |
||||
|
||||
function enhancedReducer(state, updateArg) { |
||||
// check if the type of update argument is a callback function
|
||||
if (updateArg.constructor === Function) { |
||||
return { ...state, ...updateArg(state) }; |
||||
} |
||||
|
||||
// if the type of update argument is an object
|
||||
if (updateArg.constructor === Object) { |
||||
// does the update object have _path and _value as it's keys
|
||||
// if yes then use them to update deep object values
|
||||
if (has(updateArg, "_path") && has(updateArg, "_value")) { |
||||
const { _path, _value } = updateArg; |
||||
|
||||
return produce(state, (draft) => { |
||||
set(draft, _path, _value); |
||||
}); |
||||
} else { |
||||
return { ...state, ...updateArg }; |
||||
} |
||||
} |
||||
} |
||||
|
||||
const initialState = { |
||||
firstName: "", |
||||
lastName: "", |
||||
address: { |
||||
addressLine1: "", |
||||
addressLine2: "", |
||||
pinCode: "", |
||||
}, |
||||
isMember: false, |
||||
}; |
||||
|
||||
function App() { |
||||
const [state, updateState] = React.useReducer(enhancedReducer, initialState); |
||||
|
||||
const updateForm = React.useCallback(({ target: { value, name, type } }) => { |
||||
const updatePath = name.split("."); |
||||
|
||||
// if the input is a checkbox then use callback function to update
|
||||
// the toggle state based on previous state
|
||||
if (type === "checkbox") { |
||||
updateState((prevState) => ({ |
||||
[name]: !prevState[name], |
||||
})); |
||||
|
||||
return; |
||||
} |
||||
|
||||
// if we have to update the root level nodes in the form
|
||||
if (updatePath.length === 1) { |
||||
const [key] = updatePath; |
||||
|
||||
updateState({ |
||||
[key]: value, |
||||
}); |
||||
} |
||||
|
||||
// if we have to update nested nodes in the form object
|
||||
// use _path and _value to update them.
|
||||
if (updatePath.length === 2) { |
||||
updateState({ |
||||
_path: updatePath, |
||||
_value: value, |
||||
}); |
||||
} |
||||
}, []); |
||||
|
||||
return ( |
||||
<div className="App"> |
||||
<h1>Hello, i'm your supposedly complex form.</h1> |
||||
<input |
||||
className="form-control" |
||||
type="text" |
||||
name="firstName" |
||||
placeholder="First Name" |
||||
onChange={updateForm} |
||||
value={state.firstName} |
||||
/> |
||||
<br /> |
||||
<input |
||||
className="form-control" |
||||
type="text" |
||||
name="lastName" |
||||
placeholder="Last Name" |
||||
onChange={updateForm} |
||||
value={state.lastName} |
||||
/> |
||||
<br /> |
||||
<input |
||||
className="form-control" |
||||
type="text" |
||||
name="address.addressLine1" |
||||
placeholder="Address Line One" |
||||
onChange={updateForm} |
||||
value={state.address.addressLine1} |
||||
/> |
||||
<br /> |
||||
<input |
||||
className="form-control" |
||||
type="text" |
||||
name="address.addressLine2" |
||||
placeholder="Address Line Two" |
||||
onChange={updateForm} |
||||
value={state.address.addressLine2} |
||||
/> |
||||
<br /> |
||||
<input |
||||
className="form-control" |
||||
type="text" |
||||
name="address.pinCode" |
||||
placeholder="Pincode" |
||||
onChange={updateForm} |
||||
value={state.address.pinCode} |
||||
/> |
||||
<br /> |
||||
<div className="form-check"> |
||||
<input |
||||
className="form-check-input" |
||||
type="checkbox" |
||||
name="isMember" |
||||
onChange={updateForm} |
||||
checked={state.isMember} |
||||
id="exampleCheck1" |
||||
/> |
||||
<label className="form-check-label" htmlFor="exampleCheck1"> |
||||
Are you a member already? |
||||
</label> |
||||
</div> |
||||
</div> |
||||
); |
||||
} |
||||
|
||||
const rootElement = document.getElementById("root"); |
||||
render(<App />, rootElement); |
||||
Loading…
Reference in new issue