diff --git a/exercises/src/index.css b/exercises/src/index.css
index 8470480..7d4706d 100644
--- a/exercises/src/index.css
+++ b/exercises/src/index.css
@@ -26,3 +26,58 @@ body {
flex: 3;
flex-direction: column;
}
+
+.Counter {
+ background-color: rgb(255, 255, 255);
+ list-style: none;
+ -webkit-padding-start: 0px;
+}
+.Counter__button {
+ display: inline-block;
+ -webkit-appearance: button;
+ user-select: none;
+ outline: 0px;
+ border-width: 0px;
+ border-style: initial;
+ border-color: initial;
+ border-image: initial;
+ border-radius: 4px;
+ position: relative;
+ -webkit-font-smoothing: antialiased;
+ width: 100%;
+ font-size: 18px;
+ padding: 14px 12px;
+ background-color: rgb(246, 104, 38);
+ color: white;
+ font-weight: 600;
+}
+
+.Counter__button:active {
+ opacity: 0.8;
+}
+
+.Counter__item {
+ height: 56px;
+ display: flex;
+ -webkit-box-align: center;
+ align-items: center;
+ -webkit-box-pack: justify;
+ justify-content: center;
+ position: relative;
+ border-bottom: 1px solid rgb(234, 234, 234);
+}
+
+.Counter__actions {
+ display: flex;
+ -webkit-box-align: center;
+ align-items: center;
+}
+
+.Counter__count {
+ width: 50px;
+ text-align: center;
+}
+
+.Counter__disabled {
+ opacity: 0.3;
+}
\ No newline at end of file
diff --git a/exercises/src/performance-optimizations/Count.jsx b/exercises/src/performance-optimizations/Count.jsx
new file mode 100644
index 0000000..195dd73
--- /dev/null
+++ b/exercises/src/performance-optimizations/Count.jsx
@@ -0,0 +1,43 @@
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
+
+import subtractIcon from "./icons/subtract.svg";
+import addIcon from "./icons/add.svg";
+
+export default class Count extends Component {
+ static propTypes = {
+ onIncrement: PropTypes.func,
+ onDecrement: PropTypes.func,
+ value: PropTypes.number,
+ }
+ constructor(props) {
+ super(props);
+ this.getClassNamesForButton(props);
+ }
+ getClassNamesForButton = (props) => {
+ const { value } = props;
+ this.addClassName = value >= 10 ? "Counter__disabled" : "";
+ this.subtractClassName = value <= 0 ? "Counter__disabled" : "";
+ }
+ componentWillReceiveProps(nextProps) {
+ this.getClassNamesForButton(nextProps);
+ }
+ render() {
+ const { onDecrement, value, onIncrement } = this.props;
+ return (
+
+ -
+
+
+
+
+
{ value }
+
+
+
+
+
+
+ );
+ }
+}
diff --git a/exercises/src/performance-optimizations/Counter.js b/exercises/src/performance-optimizations/Counter.js
index 3595516..4feea5f 100755
--- a/exercises/src/performance-optimizations/Counter.js
+++ b/exercises/src/performance-optimizations/Counter.js
@@ -1,10 +1,8 @@
import React, { Component, Fragment } from "react";
+import Count from "./Count";
import superExpensiveFunction from "./utils/superExpensiveFunction";
class Counter extends Component {
- static buttonStyle = {
- padding: "5px"
- };
state = {
count: 0,
timestamp: Date.now()
@@ -14,8 +12,20 @@ class Counter extends Component {
count: prevState.count + 1
});
- handleCounterClick = () => {
- this.setState(this.increment);
+ decrement = prevState => ({
+ count: prevState.count - 1
+ });
+
+ handleIncrementClick = () => {
+ if (this.state.count < 10) {
+ this.setState(this.increment);
+ }
+ };
+
+ handleDecrementClick = () => {
+ if(this.state.count > 0) {
+ this.setState(this.decrement);
+ }
};
handleDummyOperationClick = () => {
@@ -24,22 +34,21 @@ class Counter extends Component {
});
};
- shouldComponentUpdate(nextProps, nextState) {
- // Implement shouldComponentUpdate to avoid unnecessary re-renders.
- }
+ // Implement shouldComponentUpdate to avoid unnecessary re-renders.
+ // shouldComponentUpdate(nextProps, nextState) {
+ // }
render() {
const { count } = this.state;
const calculatedCount = superExpensiveFunction(count);
return (
- Clicks: {calculatedCount}
-
-
-
-
-
-
+
+
);
}
diff --git a/exercises/src/performance-optimizations/Hello.js b/exercises/src/performance-optimizations/Hello.js
deleted file mode 100755
index cacbb2a..0000000
--- a/exercises/src/performance-optimizations/Hello.js
+++ /dev/null
@@ -1,3 +0,0 @@
-import React from 'react';
-
-export default ({ name }) => Hello {name}!
;
diff --git a/exercises/src/performance-optimizations/icons/add.svg b/exercises/src/performance-optimizations/icons/add.svg
new file mode 100644
index 0000000..9e5c945
--- /dev/null
+++ b/exercises/src/performance-optimizations/icons/add.svg
@@ -0,0 +1,6 @@
+
diff --git a/exercises/src/performance-optimizations/icons/subtract.svg b/exercises/src/performance-optimizations/icons/subtract.svg
new file mode 100644
index 0000000..d9e6f93
--- /dev/null
+++ b/exercises/src/performance-optimizations/icons/subtract.svg
@@ -0,0 +1,6 @@
+
diff --git a/exercises/src/performance-optimizations/index.js b/exercises/src/performance-optimizations/index.js
index ce315d5..c86ed1a 100755
--- a/exercises/src/performance-optimizations/index.js
+++ b/exercises/src/performance-optimizations/index.js
@@ -3,14 +3,15 @@ import Counter from "./Counter";
const styles = {
fontFamily: "sans-serif",
- textAlign: "center"
+ textAlign: "center",
+ padding: "40px 120px 0"
};
-const App = () => (
+const PerformanceOptimizationExample = () => (
-
Implement shouldComponentUpdate in Counter to avoid unnecessary re-renders.
+
Implement shouldComponentUpdate in Counter & Count components to avoid unnecessary re-renders.
);
-export default App
+export default PerformanceOptimizationExample;
diff --git a/solutions/src/performance-optimizations/Count.jsx b/solutions/src/performance-optimizations/Count.jsx
new file mode 100644
index 0000000..b074620
--- /dev/null
+++ b/solutions/src/performance-optimizations/Count.jsx
@@ -0,0 +1,46 @@
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
+
+import subtractIcon from "./icons/subtract.svg";
+import addIcon from "./icons/add.svg";
+
+export default class Count extends Component {
+ static propTypes = {
+ onIncrement: PropTypes.func,
+ onDecrement: PropTypes.func,
+ value: PropTypes.number,
+ }
+ constructor(props) {
+ super(props);
+ this.getClassNamesForButton(props);
+ }
+ getClassNamesForButton = (props) => {
+ const { value } = props;
+ this.addClassName = value >= 10 ? "Counter__disabled" : "";
+ this.subtractClassName = value <= 0 ? "Counter__disabled" : "";
+ }
+ componentWillReceiveProps(nextProps) {
+ this.getClassNamesForButton(nextProps);
+ }
+ shouldComponentUpdate(nextProps, nextState) {
+ return this.props.value !== nextProps.value;
+ }
+ render() {
+ const { onDecrement, value, onIncrement } = this.props;
+ return (
+
+ -
+
+
+
+
+
{ value }
+
+
+
+
+
+
+ );
+ }
+}
diff --git a/solutions/src/performance-optimizations/Counter.js b/solutions/src/performance-optimizations/Counter.js
new file mode 100755
index 0000000..98ac054
--- /dev/null
+++ b/solutions/src/performance-optimizations/Counter.js
@@ -0,0 +1,58 @@
+import React, { Component, Fragment } from "react";
+import Count from "./Count";
+import superExpensiveFunction from "./utils/superExpensiveFunction";
+
+class Counter extends Component {
+ state = {
+ count: 0,
+ timestamp: Date.now()
+ };
+
+ increment = prevState => ({
+ count: prevState.count + 1
+ });
+
+ decrement = prevState => ({
+ count: prevState.count - 1
+ });
+
+ handleIncrementClick = () => {
+ if (this.state.count < 10) {
+ this.setState(this.increment);
+ }
+ };
+
+ handleDecrementClick = () => {
+ if(this.state.count > 0) {
+ this.setState(this.decrement);
+ }
+ };
+
+ handleDummyOperationClick = () => {
+ this.setState({
+ timestamp: Date.now()
+ });
+ };
+
+ // Implement shouldComponentUpdate to avoid unnecessary re-renders.
+ shouldComponentUpdate(nextProps, nextState) {
+ return this.state.count !== nextState.count;
+ }
+
+ render() {
+ const { count } = this.state;
+ const calculatedCount = superExpensiveFunction(count);
+ return (
+
+
+
+
+ );
+ }
+}
+
+export default Counter;
diff --git a/solutions/src/performance-optimizations/icons/add.svg b/solutions/src/performance-optimizations/icons/add.svg
new file mode 100644
index 0000000..9e5c945
--- /dev/null
+++ b/solutions/src/performance-optimizations/icons/add.svg
@@ -0,0 +1,6 @@
+
diff --git a/solutions/src/performance-optimizations/icons/subtract.svg b/solutions/src/performance-optimizations/icons/subtract.svg
new file mode 100644
index 0000000..d9e6f93
--- /dev/null
+++ b/solutions/src/performance-optimizations/icons/subtract.svg
@@ -0,0 +1,6 @@
+
diff --git a/solutions/src/performance-optimizations/index.js b/solutions/src/performance-optimizations/index.js
new file mode 100755
index 0000000..c86ed1a
--- /dev/null
+++ b/solutions/src/performance-optimizations/index.js
@@ -0,0 +1,17 @@
+import React from "react";
+import Counter from "./Counter";
+
+const styles = {
+ fontFamily: "sans-serif",
+ textAlign: "center",
+ padding: "40px 120px 0"
+};
+
+const PerformanceOptimizationExample = () => (
+
+ Implement shouldComponentUpdate in Counter & Count components to avoid unnecessary re-renders.
+
+
+);
+
+export default PerformanceOptimizationExample;
diff --git a/solutions/src/performance-optimizations/utils/superExpensiveFunction.js b/solutions/src/performance-optimizations/utils/superExpensiveFunction.js
new file mode 100755
index 0000000..b6bf31e
--- /dev/null
+++ b/solutions/src/performance-optimizations/utils/superExpensiveFunction.js
@@ -0,0 +1,6 @@
+const superExpensiveFunction = input => {
+ console.log("superExpensiveFunction");
+ return input;
+};
+
+export default superExpensiveFunction;