Currently Digit calculates the form of a concrete digit based on the prop with the name digit. The calculation is inside a nested for-loop which means we havewith a time complexity of \$O(n^2)\$\$O(n)\$. But actually the calculation is redundant since the form of a digit is known on run-time so we can reduce the time complexity to \$O(1)\$(see final result, where we do not need to loop).
Currently Digit calculates the form of a concrete digit based on the prop with the name digit. The calculation is inside a nested for-loop which means we have a time complexity of \$O(n^2)\$. But actually the calculation is redundant since the form of a digit is known on run-time so we can reduce the time complexity to \$O(1)\$.
Currently Digit calculates the form of a concrete digit based on the prop with the name digit. The calculation is inside a nested for-loop with a time complexity of \$O(n)\$. But actually the calculation is redundant since the form of a digit is known on run-time so we can reduce the time complexity (see final result, where we do not need to loop).
Consistency
Sometimes the word color or colour is used to describe the look of a Square. Because I'm not a native English speaker I looked it up on wikipedia:
color (American English), or colour (Commonwealth English)
The Algorithm
Currently Digit calculates the form of a concrete digit based on the prop with the name digit. The calculation is inside a nested for-loop which means we have a time complexity of \$O(n^2)\$. But actually the calculation is redundant since the form of a digit is known on run-time so we can reduce the time complexity to \$O(1)\$.
The form of a digit is already defined inside the array filled:
const filled = [ [ [1, 1, 1], [1, 0, 1], [1, 0, 1], [1, 0, 1], [1, 1, 1] ], /* .... */ ]
But instead of define the form based on boolean values it is possible to insert the concrete React-Components to avoid the nested for-loops:
const filled = [
[
[<Square />, <Square />, <Square />, <br />],
[<Square />, <Square colour="#FFFFFF"/>, <Square />, <br />],
[<Square />, <Square colour="#FFFFFF"/>, <Square />, <br />],
[<Square />, <Square colour="#FFFFFF"/>, <Square />, <br />],
[<Square />, <Square />, <Square />]
]
];
Expand to see the working example below
function getRandomColor() {
const colours = ["#FF6663", "#94FF63", "#63FFEA", "#A763FF", "#F2FF63"];
return colours[Math.floor(Math.random() * colours.length)];
}
class Square extends React.Component {
render() {
var squareStyle = {
width: 25,
height: 25,
backgroundColor: this.props.colour || getRandomColor(),
display: "inline-block"
};
return (
<div style={squareStyle}>
</div>
);
}
}
class Digit extends React.Component {
render() {
const divStyle = {
display: "inline-block",
lineHeight: 0,
paddingLeft: "10px",
paddingRight: "10px"
};
const filled = [
[
[<Square />, <Square />, <Square />, <br />],
[<Square />, <Square colour="#FFFFFF"/>, <Square />, <br />],
[<Square />, <Square colour="#FFFFFF"/>, <Square />, <br />],
[<Square />, <Square colour="#FFFFFF"/>, <Square />, <br />],
[<Square />, <Square />, <Square />]
]
];
return (
<div style={divStyle}>
{filled[this.props.digit]}
</div>
);
}
}
ReactDOM.render(
<div>
<Digit digit={0} />
</div>,
document.getElementById("root")
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Composition
Inside Reacts Documentation on composition is described how it can be used effectively.
Square
Currently the Square-Component can have random colors or a concrete color based on the prop. (In my opinion this is against the Single-Responsibility Principle ).
By extract the color behavior into separate components we can make the code more declarative:
const filled = [
[
[<RandomColoredSquare />, <RandomColoredSquare />, <RandomColoredSquare />, <br />],
[<RandomColoredSquare />, <EmptySquare />, <RandomColoredSquare />, <br />],
[<RandomColoredSquare />, <EmptySquare />, <RandomColoredSquare />, <br />],
[<RandomColoredSquare />, <EmptySquare />, <RandomColoredSquare />, <br />],
[<RandomColoredSquare />, <RandomColoredSquare />, <RandomColoredSquare />]
],
/* ... */
];
RandomColoredSquare and EmptySquare are specializations of Spuare:
const Square = ({color}) =>
<div style={{
width: 25,
height: 25,
backgroundColor: color,
display: "inline-block"
}}>
</div>
const RandomColoredSquare = ({colors = ["#FF6663", "#94FF63", "#63FFEA", "#A763FF", "#F2FF63"]}) =>
<Square color={colors[Math.floor(Math.random() * colors.length)]} />
const EmptySquare = _ =>
<Square color="#FFF" />
I used the the destructuring assignment to make the code more readable. Instead of const Square = ({color}) I could have written const Square = (props) but then if have to query the color with props.color and now I can use directly the color.
Additionally I make use of the default parameters together with the destructuring assignment for ({colors = ["#FF6663", "#94FF63", "#63FFEA", "#A763FF", "#F2FF63"]}).
Expand to see the working example below
const Square = ({color}) =>
<div style={{
width: 25,
height: 25,
backgroundColor: color,
display: "inline-block"
}}>
</div>
const RandomColoredSquare = ({colors = ["#FF6663", "#94FF63", "#63FFEA", "#A763FF", "#F2FF63"]}) =>
<Square color={colors[Math.floor(Math.random() * colors.length)]} />
const EmptySquare = _ =>
<Square color="#FFF" />
class Digit extends React.Component {
render() {
const divStyle = {
display: "inline-block",
lineHeight: 0,
paddingLeft: "10px",
paddingRight: "10px"
};
const filled = [
[
[<RandomColoredSquare />, <RandomColoredSquare />, <RandomColoredSquare />, <br />],
[<RandomColoredSquare />, <EmptySquare />, <RandomColoredSquare />, <br />],
[<RandomColoredSquare />, <EmptySquare />, <RandomColoredSquare />, <br />],
[<RandomColoredSquare />, <EmptySquare />, <RandomColoredSquare />, <br />],
[<RandomColoredSquare />, <RandomColoredSquare />, <RandomColoredSquare />]
]
];
return (
<div style={divStyle}>
{filled[this.props.digit]}
</div>
);
}
}
ReactDOM.render(
<div>
<Digit digit={0} />
</div>,
document.getElementById("root")
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Digit
I think <Digit digit={0} /> is a less intuitiv API then if we could simply write <Zero /> which would make our code more declarative at the first glance.
Additionally Digit violates the Open-Close Principle.
We can first describe the more generic component Digit and composite it the "special" components Zero, One and so on:
const Zero = _ =>
<Digit>
<RandomColoredSquare />
<RandomColoredSquare />
<RandomColoredSquare />
<br />
/* ... */
</Digit>
const Digit = ({children}) =>
<div style={{
display: "inline-block",
lineHeight: 0,
paddingLeft: "10px",
paddingRight: "10px"
}}>
{children}
</div>
For Digit I used the Children in JSX where it is possible to pass Components inside a component instead vie props.
Expand to see the working example below
const Square = ({color}) =>
<div style={{
width: 25,
height: 25,
backgroundColor: color,
display: "inline-block"
}}>
</div>
const RandomColoredSquare = ({colors = ["#FF6663", "#94FF63", "#63FFEA", "#A763FF", "#F2FF63"]}) =>
<Square color={colors[Math.floor(Math.random() * colors.length)]} />
const EmptySquare = _ =>
<Square color="#FFF" />
const Zero = _ =>
<Digit>
<RandomColoredSquare />
<RandomColoredSquare />
<RandomColoredSquare />
<br />
<RandomColoredSquare />
<EmptySquare />
<RandomColoredSquare />
<br />
<RandomColoredSquare />
<EmptySquare />
<RandomColoredSquare />
<br />
<RandomColoredSquare />
<EmptySquare />
<RandomColoredSquare />
<br />
<RandomColoredSquare />
<RandomColoredSquare />
<RandomColoredSquare />
</Digit>
const Digit = ({children}) =>
<div style={{
display: "inline-block",
lineHeight: 0,
paddingLeft: "10px",
paddingRight: "10px"
}}>
{children}
</div>
ReactDOM.render(
<div>
<Zero />
</div>,
document.getElementById("root")
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
But now we have this explicite <br />. We could introduce a new Component Row to make it implicit:
const Row = ({children}) =>
<div>
{children}
<br />
</div>
const Zero = _ =>
<Digit>
<Row>
<RandomColoredSquare />
<RandomColoredSquare />
<RandomColoredSquare />
</Row>
<Row>
/* ... */
</Row>
/* ... */
</Digit>
Expand to see the working example below
const Square = ({color}) =>
<div style={{
width: 25,
height: 25,
backgroundColor: color,
display: "inline-block"
}}>
</div>
const RandomColoredSquare = ({colors = ["#FF6663", "#94FF63", "#63FFEA", "#A763FF", "#F2FF63"]}) =>
<Square color={colors[Math.floor(Math.random() * colors.length)]} />
const EmptySquare = _ =>
<Square color="#FFF" />
const Row = ({children}) =>
<div>
{children}
<br />
</div>
const Zero = _ =>
<Digit>
<Row>
<RandomColoredSquare />
<RandomColoredSquare />
<RandomColoredSquare />
</Row>
<Row>
<RandomColoredSquare />
<EmptySquare />
<RandomColoredSquare />
</Row>
<Row>
<RandomColoredSquare />
<EmptySquare />
<RandomColoredSquare />
</Row>
<Row>
<RandomColoredSquare />
<EmptySquare />
<RandomColoredSquare />
</Row>
<Row>
<RandomColoredSquare />
<RandomColoredSquare />
<RandomColoredSquare />
</Row>
</Digit>
const Digit = ({children}) =>
<div style={{
display: "inline-block",
lineHeight: 0,
paddingLeft: "10px",
paddingRight: "10px"
}}>
{children}
</div>
ReactDOM.render(
<div>
<Zero />
</div>,
document.getElementById("root")
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Final Result
The result is longer since we write the digits explicit instead of create them dynamic but with this way we have a much better time complexity and the code is easier to understand since we remove the computational logic and make the code more declarative.
const Square = ({color}) =>
<div style={{
width: 25,
height: 25,
backgroundColor: color,
display: "inline-block"
}}>
</div>
const RandomColoredSquare = ({colors = ["#FF6663", "#94FF63", "#63FFEA", "#A763FF", "#F2FF63"]}) =>
<Square color={colors[Math.floor(Math.random() * colors.length)]} />
const EmptySquare = _ =>
<Square color="#FFF" />
const Row = ({children}) =>
<div>
{children}
<br />
</div>
const Zero = _ =>
<Digit>
<Row>
<RandomColoredSquare />
<RandomColoredSquare />
<RandomColoredSquare />
</Row>
<Row>
<RandomColoredSquare />
<EmptySquare />
<RandomColoredSquare />
</Row>
<Row>
<RandomColoredSquare />
<EmptySquare />
<RandomColoredSquare />
</Row>
<Row>
<RandomColoredSquare />
<EmptySquare />
<RandomColoredSquare />
</Row>
<Row>
<RandomColoredSquare />
<RandomColoredSquare />
<RandomColoredSquare />
</Row>
</Digit>
const Three = _ =>
<Digit>
<Row>
<RandomColoredSquare />
<RandomColoredSquare />
<RandomColoredSquare />
</Row>
<Row>
<EmptySquare />
<EmptySquare />
<RandomColoredSquare />
</Row>
<Row>
<EmptySquare />
<RandomColoredSquare />
<RandomColoredSquare />
</Row>
<Row>
<EmptySquare />
<EmptySquare />
<RandomColoredSquare />
</Row>
<Row>
<RandomColoredSquare />
<RandomColoredSquare />
<RandomColoredSquare />
</Row>
</Digit>
const Digit = ({children}) =>
<div style={{
display: "inline-block",
lineHeight: 0,
paddingLeft: "10px",
paddingRight: "10px"
}}>
{children}
</div>
ReactDOM.render(
<div>
<Zero />
<Three />
<Zero />
</div>,
document.getElementById("root")
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>