diff --git a/doc/HooksAPI.xmind b/doc/HooksAPI.xmind
new file mode 100644
index 0000000..54bcb1b
Binary files /dev/null and b/doc/HooksAPI.xmind differ
diff --git a/package.json b/package.json
index db6436c..c67b7b5 100644
--- a/package.json
+++ b/package.json
@@ -5,7 +5,10 @@
"dependencies": {
"react": "^16.8.6",
"react-dom": "^16.8.6",
- "react-scripts": "3.0.1"
+ "react-redux": "^7.1.0",
+ "react-router-dom": "^5.0.1",
+ "react-scripts": "3.0.1",
+ "redux": "^4.0.4"
},
"scripts": {
"start": "react-scripts start",
@@ -27,5 +30,14 @@
"last 1 firefox version",
"last 1 safari version"
]
+ },
+ "devDependencies": {
+ "jooks": "^0.0.16"
+ },
+ "jest": {
+ "collectCoverageFrom": [
+ "**/*.{js,jsx}",
+ "!**/node_modules/**"
+ ]
}
-}
+}
\ No newline at end of file
diff --git a/src/App.css b/src/App.css
deleted file mode 100644
index b41d297..0000000
--- a/src/App.css
+++ /dev/null
@@ -1,33 +0,0 @@
-.App {
- text-align: center;
-}
-
-.App-logo {
- animation: App-logo-spin infinite 20s linear;
- height: 40vmin;
- pointer-events: none;
-}
-
-.App-header {
- background-color: #282c34;
- min-height: 100vh;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- font-size: calc(10px + 2vmin);
- color: white;
-}
-
-.App-link {
- color: #61dafb;
-}
-
-@keyframes App-logo-spin {
- from {
- transform: rotate(0deg);
- }
- to {
- transform: rotate(360deg);
- }
-}
diff --git a/src/App.js b/src/App.js
index ce9cbd2..eaa0c05 100644
--- a/src/App.js
+++ b/src/App.js
@@ -1,25 +1,217 @@
-import React from 'react';
-import logo from './logo.svg';
-import './App.css';
+import React from "react";
+import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
+
+import BasicState from "./useState/BasicState";
+import MultiStates from "./useState/MultiStates";
+import ObjectState from "./useState/ObjectState";
+import InitialState from "./useState/InitialState";
+import SameState from "./useState/SameState";
+import PrevState from './useRef/PrevState';
+
+import DidEffect from "./useEffect/DidEffect";
+import UpdateEffect from "./useEffect/UpdateEffect";
+import ConditionEffect from "./useEffect/ConditionEffect";
+import ConditionEffectFromProps from "./useEffect/ConditionEffectFromProps";
+import UnmountEffect from "./useEffect/UnmountEffect";
+import MultiEffects from "./useEffect/MultiEffects";
+
+import BasicContext from "./useContext/BasicContext";
+import PropFuncContext from "./useContext/PropFuncContext";
+
+import BasicReducer from './useReducer/BasicReducer';
+import InitReducer from './useReducer/InitReducer';
+import SameReducer from './useReducer/SameReducer';
+
+import BasicCallback from "./useMemo/BasicCallback";
+
+import BasicRef from "./useRef/BasicRef";
+import StaticValueWithRef from "./useRef/StaticValueWithRef";
+import MeasureDOM from "./useRef/MeasureDom";
+
+import HOCStepOne from "./customHooks/hoc/StepOne";
+import HOCStepTwo from "./customHooks/hoc/StepTwo";
+
+import RenderPropsStepOne from './customHooks/renderProps/StepOne';
+import RenderPropsStepTwo from './customHooks/renderProps/StepTwo';
+
+import HooksStepOne from './customHooks/hooks/StepOne';
+import HooksStepTwo from './customHooks/hooks/StepTwo';
+
+import AwesomeHooks from './customHooks/awesomeHooks';
+import WithRedux from './customHooks/withLibraries/WithRedux';
function App() {
return (
-
+
+
+
+ -
+
useState demo
+
+ -
+ basic state demo
+
+ -
+ multi state demo
+
+ -
+ object state demo
+
+ -
+ initial state demo
+
+ -
+ same state demo
+
+
+
+ -
+
useEffect demo
+
+ -
+ did effect demo
+
+ -
+ update effect demo
+
+ -
+
+ condition effect demo
+
+
+ -
+
+ condition effect from props demo
+
+
+ -
+ unmount effect demo
+
+ -
+ multi effects demo
+
+
+
+
+ -
+
useContext demo
+
+ -
+ basic context demo
+
+ -
+
+ prop function context demo
+
+
+
+
+ -
+
useReducer demo
+
+ -
+ basic reducer demo
+
+ -
+
+ initial reducer demo
+
+
+ -
+
+ same reducer demo
+
+
+
+
+ -
+
useCallback demo
+
+ -
+ basic callback demo
+
+
+
+ -
+
useRef demo
+
+ -
+ basic ref demo
+
+ -
+ static value with ref demo
+
+ -
+ previous state demo
+
+ -
+ measure dom demo
+
+
+
+ -
+
custom hooks demo
+
+ -
+ HOC demo
+
+ -
+ Render props demo
+
+ -
+ Basic custom hooks demo
+
+ -
+ AwesomeHooks demo
+
+ -
+ with redux demo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
);
}
diff --git a/src/App.test.js b/src/App.test.js
deleted file mode 100644
index a754b20..0000000
--- a/src/App.test.js
+++ /dev/null
@@ -1,9 +0,0 @@
-import React from 'react';
-import ReactDOM from 'react-dom';
-import App from './App';
-
-it('renders without crashing', () => {
- const div = document.createElement('div');
- ReactDOM.render(, div);
- ReactDOM.unmountComponentAtNode(div);
-});
diff --git a/src/customHooks/awesomeHooks/__test__/useValue.test.js b/src/customHooks/awesomeHooks/__test__/useValue.test.js
new file mode 100644
index 0000000..26a7740
--- /dev/null
+++ b/src/customHooks/awesomeHooks/__test__/useValue.test.js
@@ -0,0 +1,15 @@
+import init from 'jooks';
+import useValue from '../useValue';
+
+
+describe('useValue hook', () => {
+ const jooks = init(() => useValue(3));
+
+ it('should return the times with additional text', () => {
+ // Act
+ const text = jooks.run();
+
+ // Assert
+ expect(text).toEqual(`You clicked 3 times`);
+ });
+})
\ No newline at end of file
diff --git a/src/customHooks/awesomeHooks/index.js b/src/customHooks/awesomeHooks/index.js
new file mode 100644
index 0000000..241679b
--- /dev/null
+++ b/src/customHooks/awesomeHooks/index.js
@@ -0,0 +1,20 @@
+import React, { useState } from 'react';
+import useValue from './useValue';
+import useFunction from './useFunction';
+import useComponent from './useComponent';
+
+const AwesomeHooks = () => {
+ const [state, setState] = useState(0);
+ const value = useValue(state);
+ const action = useFunction(setState);
+ const Component = useComponent(() => action(state + 1));
+
+ return (
+
+
Awesome hooks demo
+
+
+ )
+}
+
+export default AwesomeHooks;
\ No newline at end of file
diff --git a/src/customHooks/awesomeHooks/useComponent.js b/src/customHooks/awesomeHooks/useComponent.js
new file mode 100644
index 0000000..7cdab92
--- /dev/null
+++ b/src/customHooks/awesomeHooks/useComponent.js
@@ -0,0 +1,11 @@
+import React from 'react';
+
+const useComponent = (action) => {
+ const Component = ({ children }) => (
+ {children}
+ );
+
+ return Component;
+}
+
+export default useComponent;
\ No newline at end of file
diff --git a/src/customHooks/awesomeHooks/useFunction.js b/src/customHooks/awesomeHooks/useFunction.js
new file mode 100644
index 0000000..9efc9c4
--- /dev/null
+++ b/src/customHooks/awesomeHooks/useFunction.js
@@ -0,0 +1,6 @@
+const useFunction = action => {
+ console.log('loaded');
+ return action;
+}
+
+export default useFunction;
\ No newline at end of file
diff --git a/src/customHooks/awesomeHooks/useValue.js b/src/customHooks/awesomeHooks/useValue.js
new file mode 100644
index 0000000..f68518e
--- /dev/null
+++ b/src/customHooks/awesomeHooks/useValue.js
@@ -0,0 +1,5 @@
+const useValue = (value) => {
+ return `You clicked ${value} times`;
+}
+
+export default useValue;
\ No newline at end of file
diff --git a/src/customHooks/hoc/StepOne.js b/src/customHooks/hoc/StepOne.js
new file mode 100644
index 0000000..f1cffe8
--- /dev/null
+++ b/src/customHooks/hoc/StepOne.js
@@ -0,0 +1,33 @@
+import React from 'react';
+import withHOC from './withHOC';
+
+class StepOne extends React.Component {
+ constructor(...args) {
+ super(...args);
+ this.state = {
+ input: '',
+ }
+ }
+
+ render() {
+ return (
+
+ )
+ }
+
+ handleOnChange = (e) => {
+ this.setState({ input: e.target.value });
+ }
+
+ handleOnSubmit = () => {
+ const payload = { value: this.state.input };
+ this.props.onSubmit(payload);
+ this.props.history.push('/custom-hooks/hoc/step-two');
+ }
+}
+
+export default withHOC(StepOne, 'step one');
\ No newline at end of file
diff --git a/src/customHooks/hoc/StepTwo.js b/src/customHooks/hoc/StepTwo.js
new file mode 100644
index 0000000..a6f1c9a
--- /dev/null
+++ b/src/customHooks/hoc/StepTwo.js
@@ -0,0 +1,34 @@
+import React from 'react';
+import withHOC from './withHOC';
+
+class StepTwo extends React.Component {
+ constructor(...args) {
+ super(...args);
+ this.state = {
+ checked: false,
+ }
+ }
+
+ render() {
+ return (
+
+ )
+ }
+
+ handleOnClicked = () => {
+ this.setState({ checked: !this.state.checked });
+ }
+
+ handleOnSubmit = () => {
+ const payload = { value: this.state.checked ? 'checked' : 'non-checked' };
+ this.props.onSubmit(payload);
+ this.props.history.push('/custom-hooks/hoc/step-one');
+ }
+}
+
+export default withHOC(StepTwo, 'step two');
\ No newline at end of file
diff --git a/src/customHooks/hoc/withHOC.js b/src/customHooks/hoc/withHOC.js
new file mode 100644
index 0000000..cdb6f4c
--- /dev/null
+++ b/src/customHooks/hoc/withHOC.js
@@ -0,0 +1,15 @@
+import React from 'react';
+
+function withHOC(WrappedComponent, title) {
+ return class Component extends React.Component {
+ render() {
+ return
+ }
+
+ handleOnSubmit = payload => {
+ alert("title: " + title + " \npayload: " + JSON.stringify(payload));
+ }
+ }
+}
+
+export default withHOC;
\ No newline at end of file
diff --git a/src/customHooks/hooks/StepOne.js b/src/customHooks/hooks/StepOne.js
new file mode 100644
index 0000000..fa37c86
--- /dev/null
+++ b/src/customHooks/hooks/StepOne.js
@@ -0,0 +1,28 @@
+import React, { useState } from 'react';
+import useSubmit from './useSubmit';
+
+
+const StepOne = ({ history }) => {
+ const [state, setState] = useState('');
+ const onSubmit = useSubmit('step one');
+
+ const handleOnChange = (e) => {
+ setState(e.target.value);
+ }
+
+ const handleOnSubmit = () => {
+ const payload = { value: state };
+ onSubmit(payload);
+ history.push('/custom-hooks/hooks/step-two');
+ }
+
+ return (
+
+ )
+}
+
+export default StepOne;
\ No newline at end of file
diff --git a/src/customHooks/hooks/StepTwo.js b/src/customHooks/hooks/StepTwo.js
new file mode 100644
index 0000000..e1766cc
--- /dev/null
+++ b/src/customHooks/hooks/StepTwo.js
@@ -0,0 +1,28 @@
+import React, { useState } from 'react';
+import useSubmit from './useSubmit';
+
+const StepTwo = ({ history }) => {
+ const [state, setState] = useState(false);
+ const onSubmit = useSubmit('step two');
+
+ const handleOnClicked = () => {
+ setState(!state.checked);
+ }
+
+ const handleOnSubmit = () => {
+ const payload = { value: state.checked ? 'checked' : 'non-checked' };
+ onSubmit(payload);
+ history.push('/custom-hooks/hooks/step-one');
+ }
+
+ return (
+
+ )
+}
+
+export default StepTwo;
diff --git a/src/customHooks/hooks/useSubmit.js b/src/customHooks/hooks/useSubmit.js
new file mode 100644
index 0000000..e7a63dc
--- /dev/null
+++ b/src/customHooks/hooks/useSubmit.js
@@ -0,0 +1,6 @@
+
+const useSubmit = (title) => {
+ return payload => alert("title: " + title + " \npayload: " + JSON.stringify(payload));
+}
+
+export default useSubmit;
\ No newline at end of file
diff --git a/src/customHooks/renderProps/FormWrapper.js b/src/customHooks/renderProps/FormWrapper.js
new file mode 100644
index 0000000..43928d3
--- /dev/null
+++ b/src/customHooks/renderProps/FormWrapper.js
@@ -0,0 +1,14 @@
+
+import React from 'react';
+
+class FormWrapper extends React.Component {
+ render() {
+ return this.props.children(this.handleOnSubmit)
+ }
+
+ handleOnSubmit = payload => {
+ alert("title: " + this.props.title + " \npayload: " + JSON.stringify(payload));
+ }
+}
+
+export default FormWrapper;
\ No newline at end of file
diff --git a/src/customHooks/renderProps/StepOne.js b/src/customHooks/renderProps/StepOne.js
new file mode 100644
index 0000000..6b8beb1
--- /dev/null
+++ b/src/customHooks/renderProps/StepOne.js
@@ -0,0 +1,37 @@
+import React from 'react';
+import FormWrapper from './FormWrapper';
+
+class StepOne extends React.Component {
+ constructor(...args) {
+ super(...args);
+ this.state = {
+ input: '',
+ }
+ }
+
+ render() {
+ return (
+
+ {onSubmit => (
+
+ )}
+
+ )
+ }
+
+ handleOnChange = (e) => {
+ this.setState({ input: e.target.value });
+ }
+
+ handleOnSubmit = (onSubmit) => {
+ const payload = { value: this.state.input };
+ onSubmit(payload);
+ this.props.history.push('/custom-hooks/render-props/step-two');
+ }
+}
+
+export default StepOne;
\ No newline at end of file
diff --git a/src/customHooks/renderProps/StepTwo.js b/src/customHooks/renderProps/StepTwo.js
new file mode 100644
index 0000000..1268bc5
--- /dev/null
+++ b/src/customHooks/renderProps/StepTwo.js
@@ -0,0 +1,38 @@
+import React from 'react';
+import FormWrapper from './FormWrapper';
+
+class StepTwo extends React.Component {
+ constructor(...args) {
+ super(...args);
+ this.state = {
+ checked: false,
+ }
+ }
+
+ render() {
+ return (
+
+ {onSubmit => (
+
+ )}
+
+ )
+ }
+
+ handleOnClicked = () => {
+ this.setState({ checked: !this.state.checked });
+ }
+
+ handleOnSubmit = (onSubmit) => {
+ const payload = { value: this.state.checked ? 'checked' : 'non-checked' };
+ onSubmit(payload);
+ this.props.history.push('/custom-hooks/render-props/step-one');
+ }
+}
+
+export default StepTwo;
\ No newline at end of file
diff --git a/src/index.css b/src/index.css
deleted file mode 100644
index 4a1df4d..0000000
--- a/src/index.css
+++ /dev/null
@@ -1,13 +0,0 @@
-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;
-}
diff --git a/src/index.js b/src/index.js
index 87d1be5..b597a44 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,12 +1,5 @@
import React from 'react';
import ReactDOM from 'react-dom';
-import './index.css';
import App from './App';
-import * as serviceWorker from './serviceWorker';
ReactDOM.render(, document.getElementById('root'));
-
-// If you want your app to work offline and load faster, you can change
-// unregister() to register() below. Note this comes with some pitfalls.
-// Learn more about service workers: https://bit.ly/CRA-PWA
-serviceWorker.unregister();
diff --git a/src/logo.svg b/src/logo.svg
deleted file mode 100644
index 6b60c10..0000000
--- a/src/logo.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-
diff --git a/src/serviceWorker.js b/src/serviceWorker.js
deleted file mode 100644
index f8c7e50..0000000
--- a/src/serviceWorker.js
+++ /dev/null
@@ -1,135 +0,0 @@
-// This optional code is used to register a service worker.
-// register() is not called by default.
-
-// This lets the app load faster on subsequent visits in production, and gives
-// it offline capabilities. However, it also means that developers (and users)
-// will only see deployed updates on subsequent visits to a page, after all the
-// existing tabs open on the page have been closed, since previously cached
-// resources are updated in the background.
-
-// To learn more about the benefits of this model and instructions on how to
-// opt-in, read https://bit.ly/CRA-PWA
-
-const isLocalhost = Boolean(
- window.location.hostname === 'localhost' ||
- // [::1] is the IPv6 localhost address.
- window.location.hostname === '[::1]' ||
- // 127.0.0.1/8 is considered localhost for IPv4.
- window.location.hostname.match(
- /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
- )
-);
-
-export function register(config) {
- if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
- // The URL constructor is available in all browsers that support SW.
- const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
- if (publicUrl.origin !== window.location.origin) {
- // Our service worker won't work if PUBLIC_URL is on a different origin
- // from what our page is served on. This might happen if a CDN is used to
- // serve assets; see https://github.com/facebook/create-react-app/issues/2374
- return;
- }
-
- window.addEventListener('load', () => {
- const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
-
- if (isLocalhost) {
- // This is running on localhost. Let's check if a service worker still exists or not.
- checkValidServiceWorker(swUrl, config);
-
- // Add some additional logging to localhost, pointing developers to the
- // service worker/PWA documentation.
- navigator.serviceWorker.ready.then(() => {
- console.log(
- 'This web app is being served cache-first by a service ' +
- 'worker. To learn more, visit https://bit.ly/CRA-PWA'
- );
- });
- } else {
- // Is not localhost. Just register service worker
- registerValidSW(swUrl, config);
- }
- });
- }
-}
-
-function registerValidSW(swUrl, config) {
- navigator.serviceWorker
- .register(swUrl)
- .then(registration => {
- registration.onupdatefound = () => {
- const installingWorker = registration.installing;
- if (installingWorker == null) {
- return;
- }
- installingWorker.onstatechange = () => {
- if (installingWorker.state === 'installed') {
- if (navigator.serviceWorker.controller) {
- // At this point, the updated precached content has been fetched,
- // but the previous service worker will still serve the older
- // content until all client tabs are closed.
- console.log(
- 'New content is available and will be used when all ' +
- 'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
- );
-
- // Execute callback
- if (config && config.onUpdate) {
- config.onUpdate(registration);
- }
- } else {
- // At this point, everything has been precached.
- // It's the perfect time to display a
- // "Content is cached for offline use." message.
- console.log('Content is cached for offline use.');
-
- // Execute callback
- if (config && config.onSuccess) {
- config.onSuccess(registration);
- }
- }
- }
- };
- };
- })
- .catch(error => {
- console.error('Error during service worker registration:', error);
- });
-}
-
-function checkValidServiceWorker(swUrl, config) {
- // Check if the service worker can be found. If it can't reload the page.
- fetch(swUrl)
- .then(response => {
- // Ensure service worker exists, and that we really are getting a JS file.
- const contentType = response.headers.get('content-type');
- if (
- response.status === 404 ||
- (contentType != null && contentType.indexOf('javascript') === -1)
- ) {
- // No service worker found. Probably a different app. Reload the page.
- navigator.serviceWorker.ready.then(registration => {
- registration.unregister().then(() => {
- window.location.reload();
- });
- });
- } else {
- // Service worker found. Proceed as normal.
- registerValidSW(swUrl, config);
- }
- })
- .catch(() => {
- console.log(
- 'No internet connection found. App is running in offline mode.'
- );
- });
-}
-
-export function unregister() {
- if ('serviceWorker' in navigator) {
- navigator.serviceWorker.ready.then(registration => {
- registration.unregister();
- });
- }
-}
diff --git a/src/useContext/BasicContext.js b/src/useContext/BasicContext.js
new file mode 100644
index 0000000..552681b
--- /dev/null
+++ b/src/useContext/BasicContext.js
@@ -0,0 +1,42 @@
+import React, { useState, useContext } from "react";
+import { MyContext } from "./theme-context";
+
+const AnotherButton = ({ changeColor }) => {
+ const color = useContext(MyContext);
+ return (
+
+ );
+};
+
+const ThemedButton = ({ changeColor }) => {
+ const color = useContext(MyContext);
+ return (
+
+
+
+
+
+
+ );
+};
+const BasicContext = () => {
+ const [color, setColor] = useState("blue");
+
+ return (
+
+
+
+ );
+};
+
+export default BasicContext;
diff --git a/src/useContext/PropFuncContext.js b/src/useContext/PropFuncContext.js
new file mode 100644
index 0000000..007e1e2
--- /dev/null
+++ b/src/useContext/PropFuncContext.js
@@ -0,0 +1,42 @@
+import React, { useState, useContext } from "react";
+import { MyContext } from "./theme-context";
+
+const AnotherButton = () => {
+ const { color, setColor } = useContext(MyContext);
+ return (
+
+ );
+};
+
+const ThemedButton = () => {
+ const { color, setColor } = useContext(MyContext);
+ return (
+
+
+
+
+
+
+ );
+};
+const PropFuncContext = () => {
+ const [color, setColor] = useState("blue");
+
+ return (
+
+
+
+ );
+};
+
+export default PropFuncContext;
diff --git a/src/useContext/theme-context.js b/src/useContext/theme-context.js
new file mode 100644
index 0000000..c635d37
--- /dev/null
+++ b/src/useContext/theme-context.js
@@ -0,0 +1,3 @@
+import React from "react";
+
+export const MyContext = React.createContext();
diff --git a/src/useEffect/ConditionEffect.js b/src/useEffect/ConditionEffect.js
new file mode 100644
index 0000000..68ee173
--- /dev/null
+++ b/src/useEffect/ConditionEffect.js
@@ -0,0 +1,25 @@
+import React, { useState, useEffect } from 'react';
+
+const ConditionEffect = () => {
+ const [fruit, setFruit] = useState(0);
+ const [vegetable, setVegetable] = useState(1);
+
+ useEffect(() => {
+ alert(`you clicked ${fruit} times`);
+ }, [fruit]);
+
+ return (
+
+
Condition Effect example
+
You clicked fruit {fruit} times
+
+
You clicked vegetable {vegetable} times
+
+
);
+}
+
+export default ConditionEffect;
\ No newline at end of file
diff --git a/src/useEffect/ConditionEffectFromProps.js b/src/useEffect/ConditionEffectFromProps.js
new file mode 100644
index 0000000..556fa70
--- /dev/null
+++ b/src/useEffect/ConditionEffectFromProps.js
@@ -0,0 +1,29 @@
+import React, { useState, useEffect } from 'react';
+
+const EffectItem = ({ fruit }) => {
+ useEffect(() => {
+ alert(`you clicked ${fruit} times`);
+ }, [fruit]);
+
+ return You clicked fruit {fruit} times
;
+}
+
+const ConditionEffectFromProps = () => {
+ const [fruit, setFruit] = useState(0);
+ const [vegetable, setVegetable] = useState(1);
+
+ return (
+
+
Condition Effect From Props example
+
+
+
You clicked vegetable {vegetable} times
+
+
);
+}
+
+export default ConditionEffectFromProps;
\ No newline at end of file
diff --git a/src/useEffect/DidEffect.js b/src/useEffect/DidEffect.js
new file mode 100644
index 0000000..794e4b7
--- /dev/null
+++ b/src/useEffect/DidEffect.js
@@ -0,0 +1,21 @@
+import React, { useState, useEffect } from 'react';
+
+const DidEffect = () => {
+ const [count, setCount] = useState(0);
+
+ useEffect(() => {
+ alert(`page loaded`);
+ }, []);
+
+
+ return (
+
+
Did effect example
+
You clicked {count} times
+
+
);
+}
+
+export default DidEffect;
\ No newline at end of file
diff --git a/src/useEffect/MultiEffects.js b/src/useEffect/MultiEffects.js
new file mode 100644
index 0000000..48260b1
--- /dev/null
+++ b/src/useEffect/MultiEffects.js
@@ -0,0 +1,25 @@
+import React, { useState, useEffect } from "react";
+
+const MultiEffects = () => {
+ const [count, setCount] = useState(0);
+
+ useEffect(() => {
+ alert(`page loaded 1`);
+ });
+ useEffect(() => {
+ alert(`page loaded 2`);
+ });
+ useEffect(() => {
+ alert(`page loaded 3`);
+ });
+
+ return (
+
+
Basic effect example
+
You clicked {count} times
+
+
+ );
+};
+
+export default MultiEffects;
diff --git a/src/useEffect/UnmountEffect.js b/src/useEffect/UnmountEffect.js
new file mode 100644
index 0000000..af8d08b
--- /dev/null
+++ b/src/useEffect/UnmountEffect.js
@@ -0,0 +1,15 @@
+import React, { useEffect } from "react";
+
+const UnmountEffect = () => {
+ useEffect(() => {
+ return () => alert("page is about to unmount");
+ });
+
+ return (
+
+
Unmount state example
+
+ );
+};
+
+export default UnmountEffect;
diff --git a/src/useEffect/UpdateEffect.js b/src/useEffect/UpdateEffect.js
new file mode 100644
index 0000000..9633c79
--- /dev/null
+++ b/src/useEffect/UpdateEffect.js
@@ -0,0 +1,22 @@
+import React, { useState, useEffect } from 'react';
+
+const UpdateEffect = () => {
+ const [count, setCount] = useState(0);
+
+ useEffect(() => {
+ document.title = `You clicked ${count} times`;
+ });
+
+
+ return (
+
+
Basic effect example
+
You clicked {count} times
+
+
+ );
+}
+
+export default UpdateEffect;
\ No newline at end of file
diff --git a/src/useEffect/__test__/updataEffect.test.js b/src/useEffect/__test__/updataEffect.test.js
new file mode 100644
index 0000000..a350b27
--- /dev/null
+++ b/src/useEffect/__test__/updataEffect.test.js
@@ -0,0 +1,34 @@
+import React from 'react';
+import ReactDOM from 'react-dom';
+import { act } from 'react-dom/test-utils';
+import UpdateEffect from '../UpdateEffect';
+
+let container;
+
+beforeEach(() => {
+ container = document.createElement('div');
+ document.body.appendChild(container);
+});
+
+afterEach(() => {
+ document.body.removeChild(container);
+ container = null;
+});
+
+it('can render and update a counter', () => {
+ // 测试首次渲染和 effect
+ act(() => {
+ ReactDOM.render(, container);
+ });
+ const button = container.querySelector('button');
+ const label = container.querySelector('p');
+ expect(label.textContent).toBe('You clicked 0 times');
+ expect(document.title).toBe('You clicked 0 times');
+
+ // 测试第二次渲染和 effect
+ act(() => {
+ button.dispatchEvent(new MouseEvent('click', { bubbles: true }));
+ });
+ expect(label.textContent).toBe('You clicked 1 times');
+ expect(document.title).toBe('You clicked 1 times');
+});
\ No newline at end of file
diff --git a/src/useMemo/BasicCallback.js b/src/useMemo/BasicCallback.js
new file mode 100644
index 0000000..efcd340
--- /dev/null
+++ b/src/useMemo/BasicCallback.js
@@ -0,0 +1,23 @@
+import React, { useState, useCallback, useMemo } from 'react';
+
+const BasicCallback = () => {
+ const [state, changeState] = useState({});
+ const memorizedValue = useMemo(() => Math.random(), []);
+ const memorizedCallback = useCallback(() => console.log(memorizedValue), [memorizedValue]);
+ const unMemorizedCallback = () => console.log(memorizedValue);
+ const { prevMemorizedCallback, prevUnMemorizedCallback } = state;
+
+ return (
+
+
Memorized value: {memorizedValue}
+
New update {Math.random()}
+
is prevMemorizedCallback === to memorizedCallback: {String(prevMemorizedCallback === memorizedCallback)}
+
is prevUnMemorizedCallback === to unMemorizedCallback: {String(prevUnMemorizedCallback === unMemorizedCallback)}
+
+
+
+
+ );
+};
+
+export default BasicCallback;
\ No newline at end of file
diff --git a/src/useReducer/BasicReducer.js b/src/useReducer/BasicReducer.js
new file mode 100644
index 0000000..de21e73
--- /dev/null
+++ b/src/useReducer/BasicReducer.js
@@ -0,0 +1,28 @@
+import React, { useReducer } from 'react';
+
+const initialState = { count: 0 };
+
+const reducer = (state, action) => {
+ switch (action.type) {
+ case 'increment':
+ return { count: state.count + 1 };
+ case 'decrement':
+ return { count: state.count - 1 };
+ default:
+ throw new Error();
+ }
+}
+
+const BasicReducer = () => {
+ const [state, dispatch] = useReducer(reducer, initialState);
+ return (
+
+
Basic reducer demo
+ Count: {state.count}
+
+
+
+ );
+}
+
+export default BasicReducer;
\ No newline at end of file
diff --git a/src/useReducer/InitReducer.js b/src/useReducer/InitReducer.js
new file mode 100644
index 0000000..0635433
--- /dev/null
+++ b/src/useReducer/InitReducer.js
@@ -0,0 +1,39 @@
+import React, { useReducer } from 'react';
+
+const init = (initialCount) => {
+ return initialCount;
+}
+
+const initialCount = { count: 0 };
+
+const reducer = (state, action) => {
+ switch (action.type) {
+ case 'increment':
+ return { count: state.count + 1 };
+ case 'decrement':
+ return { count: state.count - 1 };
+ case 'reset':
+ return init(action.payload);
+ default:
+ throw new Error();
+ }
+}
+
+const InitReducer = () => {
+ const [state, dispatch] = useReducer(reducer, initialCount, init);
+ return (
+
+
Basic reducer demo
+ Count: {state.count}
+
+
+
+
+ );
+}
+
+export default InitReducer;
\ No newline at end of file
diff --git a/src/useReducer/SameReducer.js b/src/useReducer/SameReducer.js
new file mode 100644
index 0000000..c794136
--- /dev/null
+++ b/src/useReducer/SameReducer.js
@@ -0,0 +1,32 @@
+import React, { useReducer, useEffect } from 'react';
+
+const initialState = { count: 0 };
+
+const reducer = (state, action) => {
+ switch (action.type) {
+ case 'increment':
+ return { count: state.count + 1 };
+ case 'decrement':
+ return { count: state.count - 1 };
+ case 'sameState':
+ return state;
+ default:
+ throw new Error();
+ }
+}
+
+const SameReducer = () => {
+ const [state, dispatch] = useReducer(reducer, initialState);
+ useEffect(() => alert('page reloaded'));
+ return (
+
+
same reducer demo
+ Count: {state.count}
+
+
+
+
+ );
+}
+
+export default SameReducer;
\ No newline at end of file
diff --git a/src/useRef/BasicRef.js b/src/useRef/BasicRef.js
new file mode 100644
index 0000000..422ff53
--- /dev/null
+++ b/src/useRef/BasicRef.js
@@ -0,0 +1,18 @@
+import React, { useRef } from 'react';
+
+const BasicRef = () => {
+ const inputEl = useRef(null);
+ const onButtonClick = () => {
+ inputEl.current.focus();
+ };
+ console.log('inputEl: ', inputEl);
+
+ return (
+
+
+
+
+ );
+}
+
+export default BasicRef;
\ No newline at end of file
diff --git a/src/useRef/MeasureDom.js b/src/useRef/MeasureDom.js
new file mode 100644
index 0000000..7eff665
--- /dev/null
+++ b/src/useRef/MeasureDom.js
@@ -0,0 +1,24 @@
+import React, { useRef, useState, useCallback } from 'react';
+
+function MeasureDOM() {
+ const [height, setHeight] = useState(0);
+ const domRef = useRef();
+
+ const measuredRef = useCallback(node => {
+ if (node !== null) {
+ setHeight(node.getBoundingClientRect().height);
+ }
+ }, []);
+
+ return (
+
+
Hello, world
+ The above header is {Math.round(height)}px tall
+ Hello
+ height: {domRef.current && domRef.current.style.height}
+ width: {domRef.current && domRef.current.style.width}
+
+ );
+}
+
+export default MeasureDOM;
\ No newline at end of file
diff --git a/src/useRef/PrevState.js b/src/useRef/PrevState.js
new file mode 100644
index 0000000..1d1744b
--- /dev/null
+++ b/src/useRef/PrevState.js
@@ -0,0 +1,22 @@
+import React, { useState, useRef, useEffect } from 'react';
+
+const PrevState = () => {
+ const [count, setCount] = useState(0);
+ const prevCountRef = useRef();
+ useEffect(() => {
+ prevCountRef.current = count;
+ });
+ const prevCount = prevCountRef.current;
+
+ return (
+
+
previous state example
+
You clicked {count} times
+
+
Now: {count}, before: {prevCount}
+
);
+}
+
+export default PrevState;
\ No newline at end of file
diff --git a/src/useRef/StaticValueWithRef.js b/src/useRef/StaticValueWithRef.js
new file mode 100644
index 0000000..6e9b658
--- /dev/null
+++ b/src/useRef/StaticValueWithRef.js
@@ -0,0 +1,28 @@
+import React, { useState, useEffect, useRef } from 'react';
+
+const StaticValueWithRef = () => {
+ const [state, setState] = useState(0);
+ const intervalRef = useRef();
+
+ useEffect(() => {
+ intervalRef.current = setInterval(() => {
+ setState(state + 1);
+ }, 30);
+
+ return () => {
+ clearInterval(intervalRef.current);
+ };
+ });
+
+ return
+
{state}
+
+
+
+
+}
+
+export default StaticValueWithRef;
\ No newline at end of file
diff --git a/src/useState/BasicState.js b/src/useState/BasicState.js
new file mode 100644
index 0000000..be1c536
--- /dev/null
+++ b/src/useState/BasicState.js
@@ -0,0 +1,16 @@
+import React, { useState } from 'react';
+
+const BasicState = () => {
+ const [count, setCount] = useState(0);
+
+ return (
+
+
Basic state example
+
You clicked {count} times
+
+
);
+}
+
+export default BasicState;
\ No newline at end of file
diff --git a/src/useState/InitialState.js b/src/useState/InitialState.js
new file mode 100644
index 0000000..7471f29
--- /dev/null
+++ b/src/useState/InitialState.js
@@ -0,0 +1,18 @@
+import React, { useState } from "react";
+
+const InitialState = () => {
+ const [count, setCount] = useState(() => {
+ alert("page loaded");
+ return 0;
+ });
+
+ return (
+
+
Initial state example
+
You clicked {count} times
+
+
+ );
+};
+
+export default InitialState;
diff --git a/src/useState/MultiStates.js b/src/useState/MultiStates.js
new file mode 100644
index 0000000..b2b8c33
--- /dev/null
+++ b/src/useState/MultiStates.js
@@ -0,0 +1,26 @@
+import React, { useState } from 'react';
+
+const MultiStateExample = () => {
+ const [fruit, setFruit] = useState(0);
+ const [vegetable, setVegetable] = useState(1);
+ const [cereals, setCereals] = useState(2);
+
+ return (
+
+
Multi state example
+
You clicked fruit {fruit} times
+
+
You clicked vegetable {vegetable} times
+
+
You clicked cereals {cereals} times
+
+
);
+}
+
+export default MultiStateExample;
\ No newline at end of file
diff --git a/src/useState/ObjectState.js b/src/useState/ObjectState.js
new file mode 100644
index 0000000..128af75
--- /dev/null
+++ b/src/useState/ObjectState.js
@@ -0,0 +1,21 @@
+import React, { useState } from "react";
+
+const ObjectState = () => {
+ const [state, setState] = useState({ fruit: 0, vegetable: 1 });
+
+ return (
+
+
Multi state example
+
You clicked fruit {state.fruit} times
+
+
You clicked vegetable {state.vegetable} times
+
+
+ );
+};
+
+export default ObjectState;
diff --git a/src/useState/SameState.js b/src/useState/SameState.js
new file mode 100644
index 0000000..294e5a3
--- /dev/null
+++ b/src/useState/SameState.js
@@ -0,0 +1,27 @@
+import React, { useState, useEffect } from "react";
+
+const EffectItem = () => {
+ useEffect(() => {
+ alert(`component loaded`);
+ });
+
+ return You clicked fruit
;
+};
+
+const SameState = () => {
+ const [fruit, setFruit] = useState(0);
+
+ useEffect(() => {
+ alert(`page loaded`);
+ });
+
+ return (
+
+
Multi state example
+
+
+
+ );
+};
+
+export default SameState;
diff --git a/yarn.lock b/yarn.lock
index 25b6936..e558886 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -859,6 +859,20 @@
dependencies:
regenerator-runtime "^0.13.2"
+"@babel/runtime@^7.1.2", "@babel/runtime@^7.4.0":
+ version "7.5.4"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.5.4.tgz#cb7d1ad7c6d65676e66b47186577930465b5271b"
+ integrity sha512-Na84uwyImZZc3FKf4aUF1tysApzwf3p2yuFBIyBfbzT5glzKTdvYI4KVW4kcgjrzoGUjC7w3YyCHcJKaRxsr2Q==
+ dependencies:
+ regenerator-runtime "^0.13.2"
+
+"@babel/runtime@^7.4.5":
+ version "7.5.5"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.5.5.tgz#74fba56d35efbeca444091c7850ccd494fd2f132"
+ integrity sha512-28QvEGyQyNkB0/m2B4FU7IEZGK2NUrcMtT6BZEFALTguLk+AUT6ofsHtPk5QyjAdUkpMJ+/Em+quwz4HOt30AQ==
+ dependencies:
+ regenerator-runtime "^0.13.2"
+
"@babel/template@^7.1.0", "@babel/template@^7.4.0", "@babel/template@^7.4.4":
version "7.4.4"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.4.4.tgz#f4b88d1225689a08f5bc3a17483545be9e4ed237"
@@ -4268,6 +4282,11 @@ growly@^1.3.0:
resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=
+gud@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/gud/-/gud-1.0.0.tgz#a489581b17e6a70beca9abe3ae57de7a499852c0"
+ integrity sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw==
+
gzip-size@5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-5.0.0.tgz#a55ecd99222f4c48fd8c01c625ce3b349d0a0e80"
@@ -4422,6 +4441,18 @@ hex-color-regex@^1.1.0:
resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e"
integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==
+history@^4.9.0:
+ version "4.9.0"
+ resolved "https://registry.yarnpkg.com/history/-/history-4.9.0.tgz#84587c2068039ead8af769e9d6a6860a14fa1bca"
+ integrity sha512-H2DkjCjXf0Op9OAr6nJ56fcRkTSNrUiv41vNJ6IswJjif6wlpZK0BTfFbi7qK9dXLSYZxkq5lBsj3vUjlYBYZA==
+ dependencies:
+ "@babel/runtime" "^7.1.2"
+ loose-envify "^1.2.0"
+ resolve-pathname "^2.2.0"
+ tiny-invariant "^1.0.2"
+ tiny-warning "^1.0.0"
+ value-equal "^0.4.0"
+
hmac-drbg@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
@@ -4431,6 +4462,13 @@ hmac-drbg@^1.0.0:
minimalistic-assert "^1.0.0"
minimalistic-crypto-utils "^1.0.1"
+hoist-non-react-statics@^3.1.0, 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"
+
hosted-git-info@^2.1.4:
version "2.7.1"
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047"
@@ -5041,6 +5079,11 @@ is-wsl@^1.1.0:
resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d"
integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=
+isarray@0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
+ integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=
+
isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
@@ -5497,6 +5540,13 @@ jest@24.7.1:
import-local "^2.0.0"
jest-cli "^24.7.1"
+jooks@^0.0.16:
+ version "0.0.16"
+ resolved "https://registry.yarnpkg.com/jooks/-/jooks-0.0.16.tgz#0b5c47e3bbf3f6014b7b72a8e8dc3ad3da901006"
+ integrity sha512-8cYg1y14Raweo1F85rZ8DvAKGYckGn+YGJ+RIpj6njSj4V+Wqbv7qvmxEeDmXO0/S6fJ+e7owFBtIe0Nfbh2sQ==
+ dependencies:
+ lodash "^4.17.11"
+
js-levenshtein@^1.1.3:
version "1.1.6"
resolved "https://registry.yarnpkg.com/js-levenshtein/-/js-levenshtein-1.1.6.tgz#c6cee58eb3550372df8deb85fad5ce66ce01d59d"
@@ -5876,7 +5926,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.1.0, loose-envify@^1.4.0:
+loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, 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==
@@ -6065,6 +6115,15 @@ mimic-fn@^2.0.0:
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
+mini-create-react-context@^0.3.0:
+ version "0.3.2"
+ resolved "https://registry.yarnpkg.com/mini-create-react-context/-/mini-create-react-context-0.3.2.tgz#79fc598f283dd623da8e088b05db8cddab250189"
+ integrity sha512-2v+OeetEyliMt5VHMXsBhABoJ0/M4RCe7fatd/fBy6SMiKazUSEt3gxxypfnk2SHMkdBYvorHRoQxuGoiwbzAw==
+ dependencies:
+ "@babel/runtime" "^7.4.0"
+ gud "^1.0.0"
+ tiny-warning "^1.0.2"
+
mini-css-extract-plugin@0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.5.0.tgz#ac0059b02b9692515a637115b0cc9fed3a35c7b0"
@@ -6813,6 +6872,13 @@ path-to-regexp@0.1.7:
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
+path-to-regexp@^1.7.0:
+ version "1.7.0"
+ resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.7.0.tgz#59fde0f435badacba103a84e9d3bc64e96b9937d"
+ integrity sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=
+ dependencies:
+ isarray "0.0.1"
+
path-type@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73"
@@ -7645,7 +7711,7 @@ prompts@^2.0.1:
kleur "^3.0.2"
sisteransi "^1.0.0"
-prop-types@^15.6.2:
+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==
@@ -7846,7 +7912,7 @@ react-dev-utils@^9.0.1:
strip-ansi "5.2.0"
text-table "0.2.0"
-react-dom@16.8.6:
+react-dom@^16.8.6:
version "16.8.6"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.8.6.tgz#71d6303f631e8b0097f56165ef608f051ff6e10f"
integrity sha512-1nL7PIq9LTL3fthPqwkvr2zY7phIPjYrT0jp4HjyEQrEROnw4dG41VVwi/wfoCneoleqrNX7iAD+pXebJZwrwA==
@@ -7861,11 +7927,52 @@ react-error-overlay@^5.1.6:
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-5.1.6.tgz#0cd73407c5d141f9638ae1e0c63e7b2bf7e9929d"
integrity sha512-X1Y+0jR47ImDVr54Ab6V9eGk0Hnu7fVWGeHQSOXHf/C2pF9c6uy3gef8QUeuUiWlNb0i08InPSE5a/KJzNzw1Q==
-react-is@^16.8.1, react-is@^16.8.4:
+react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.4, react-is@^16.8.6:
version "16.8.6"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.6.tgz#5bbc1e2d29141c9fbdfed456343fe2bc430a6a16"
integrity sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA==
+react-redux@^7.1.0:
+ version "7.1.0"
+ resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.1.0.tgz#72af7cf490a74acdc516ea9c1dd80e25af9ea0b2"
+ integrity sha512-hyu/PoFK3vZgdLTg9ozbt7WF3GgX5+Yn3pZm5/96/o4UueXA+zj08aiSC9Mfj2WtD1bvpIb3C5yvskzZySzzaw==
+ dependencies:
+ "@babel/runtime" "^7.4.5"
+ 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.6"
+
+react-router-dom@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.0.1.tgz#ee66f4a5d18b6089c361958e443489d6bab714be"
+ integrity sha512-zaVHSy7NN0G91/Bz9GD4owex5+eop+KvgbxXsP/O+iW1/Ln+BrJ8QiIR5a6xNPtrdTvLkxqlDClx13QO1uB8CA==
+ dependencies:
+ "@babel/runtime" "^7.1.2"
+ history "^4.9.0"
+ loose-envify "^1.3.1"
+ prop-types "^15.6.2"
+ react-router "5.0.1"
+ tiny-invariant "^1.0.2"
+ tiny-warning "^1.0.0"
+
+react-router@5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/react-router/-/react-router-5.0.1.tgz#04ee77df1d1ab6cb8939f9f01ad5702dbadb8b0f"
+ integrity sha512-EM7suCPNKb1NxcTZ2LEOWFtQBQRQXecLxVpdsP4DW4PbbqYWeRiLyV/Tt1SdCrvT2jcyXAXmVTmzvSzrPR63Bg==
+ dependencies:
+ "@babel/runtime" "^7.1.2"
+ history "^4.9.0"
+ hoist-non-react-statics "^3.1.0"
+ loose-envify "^1.3.1"
+ mini-create-react-context "^0.3.0"
+ path-to-regexp "^1.7.0"
+ prop-types "^15.6.2"
+ react-is "^16.6.0"
+ tiny-invariant "^1.0.2"
+ tiny-warning "^1.0.0"
+
react-scripts@3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/react-scripts/-/react-scripts-3.0.1.tgz#e5565350d8069cc9966b5998d3fe3befe3d243ac"
@@ -7926,7 +8033,7 @@ react-scripts@3.0.1:
optionalDependencies:
fsevents "2.0.6"
-react@16.8.6:
+react@^16.8.6:
version "16.8.6"
resolved "https://registry.yarnpkg.com/react/-/react-16.8.6.tgz#ad6c3a9614fd3a4e9ef51117f54d888da01f2bbe"
integrity sha512-pC0uMkhLaHm11ZSJULfOBqV4tIZkx87ZLvbbQYunNixAAvjnC+snJCg0XQXn9VIsttVsbZP/H/ewzgsd5fxKXw==
@@ -8015,6 +8122,14 @@ recursive-readdir@2.2.2:
dependencies:
minimatch "3.0.4"
+redux@^4.0.4:
+ version "4.0.4"
+ resolved "https://registry.yarnpkg.com/redux/-/redux-4.0.4.tgz#4ee1aeb164b63d6a1bcc57ae4aa0b6e6fa7a3796"
+ integrity sha512-vKv4WdiJxOWKxK0yRoaK3Y4pxxB0ilzVx6dszU2W8wLxlb2yikRph4iV/ymtdJ6ZxpBLFbyrxklnT5yBbQSl3Q==
+ dependencies:
+ loose-envify "^1.4.0"
+ symbol-observable "^1.2.0"
+
regenerate-unicode-properties@^8.0.2:
version "8.0.2"
resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.0.2.tgz#7b38faa296252376d363558cfbda90c9ce709662"
@@ -8220,6 +8335,11 @@ resolve-from@^4.0.0:
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
+resolve-pathname@^2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-2.2.0.tgz#7e9ae21ed815fd63ab189adeee64dc831eefa879"
+ integrity sha512-bAFz9ld18RzJfddgrO2e/0S2O81710++chRMUxHjXOYKF6jTAMrUNZrEZ1PvV0zlhfjidm08iRPdTLPno1FuRg==
+
resolve-url@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
@@ -8979,6 +9099,11 @@ svgo@^1.0.0, svgo@^1.2.1:
unquote "~1.1.1"
util.promisify "~1.0.0"
+symbol-observable@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804"
+ integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==
+
symbol-tree@^3.2.2:
version "3.2.2"
resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6"
@@ -9085,6 +9210,16 @@ timsort@^0.3.0:
resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4"
integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=
+tiny-invariant@^1.0.2:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.0.6.tgz#b3f9b38835e36a41c843a3b0907a5a7b3755de73"
+ integrity sha512-FOyLWWVjG+aC0UqG76V53yAWdXfH8bO6FNmyZOuUrzDzK8DI3/JRY25UD7+g49JWM1LXwymsKERB+DzI0dTEQA==
+
+tiny-warning@^1.0.0, tiny-warning@^1.0.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754"
+ integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==
+
tmp@^0.0.33:
version "0.0.33"
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
@@ -9443,6 +9578,11 @@ validate-npm-package-license@^3.0.1:
spdx-correct "^3.0.0"
spdx-expression-parse "^3.0.0"
+value-equal@^0.4.0:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-0.4.0.tgz#c5bdd2f54ee093c04839d71ce2e4758a6890abc7"
+ integrity sha512-x+cYdNnaA3CxvMaTX0INdTCN8m8aF2uY9BvEqmxuYp8bL09cs/kWVQPVGcA35fMktdOsP69IgU7wFj/61dJHEw==
+
vary@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"