I am slowly digesting React.js, found couple of ways to write the same piece of code: Please tell where all I went wrong in below code.
- I try to put logic inside
render()
, is that Ok? - Not using React life cycles for simple components?
- Use Functional components instead of class components?
File 1: batch_progress.js
Description: Shows batch progress, expects 3 values:
- current batch.
- target batch count.
- state of the batch (based on which the progress bar color changes).
import React, { Component } from 'react';
import ProgressBar from '../progress_bar/progress_bar';
export default class BatchStatus extends Component {
constructor(props) {
super(props);
}
render() {
let color;
let percentage = (this.props.batch.number / this.props.targetBatchCount) * 100;
switch (this.props.batch.status) {
case 100:
color = '#e7e4f1';
break;
case 200:
color = '#c3dcec';
break;
case 300:
color = '#ecc6eb';
break;
case 400:
color = '#ecdec3';
break;
case 500:
color = '#c8ecc7';
break;
default:
color = '#e7e4f1';
}
return (
<ProgressBar foregroundColor={color} percentage={percentage}>
{this.props.batch.number} / {this.props.targetBatchCount}
</ProgressBar>
);
}
}
File 2: progress_bar.js
import React, { Component } from 'react';
import './progress_bar.css';
export default class ProgressBar extends Component {
constructor(props) {
super(props);
}
render() {
let foregroundColor = this.props.foregroundColor || '#e7e4f1';
let percentage = this.props.percentage || 0;
let backgroundColor = this.props.backgroundColor || '#eceeef';
let style = {
backgroundImage:
'linear-gradient(to right, ' +
foregroundColor +
' ' +
percentage +
'%, ' +
backgroundColor +
' 0%)'
};
return (
<div className="progress-bar-container" style={style}>
{this.props.children}
</div>
);
}
}
-
3\$\begingroup\$ Please edit your question to include some details of what the code Is supposed to do. Also a brief description should go to the title. People Are more likely to want to review a progrese bar in react than they want to review random shapeless react code that they dont know what should be doing. \$\endgroup\$slepic– slepic2020年03月07日 08:25:06 +00:00Commented Mar 7, 2020 at 8:25
-
2\$\begingroup\$ Your title is too generic. It should state what your code does. \$\endgroup\$BCdotWEB– BCdotWEB2020年03月09日 16:21:57 +00:00Commented Mar 9, 2020 at 16:21
-
\$\begingroup\$ @BCdotWEB edited the question... if not good you can edit it as well. \$\endgroup\$Dheemanth Bhat– Dheemanth Bhat2020年03月10日 05:30:27 +00:00Commented Mar 10, 2020 at 5:30
-
2\$\begingroup\$ @Pure'ajax I don't know what your code does, you're supposed to tell us. The current question title, which states your concerns about the code, is too general to be useful here. Please edit to the site standard, which is for the title to simply state the task accomplished by the code. Please see How to get the best value out of Code Review: Asking Questions for guidance on writing good question titles. \$\endgroup\$BCdotWEB– BCdotWEB2020年03月10日 13:17:00 +00:00Commented Mar 10, 2020 at 13:17
-
1\$\begingroup\$ I changed the title so that it describes what the code does per site goals: "State what your code does in your title, not your main concerns about it.". Feel free to edit and give it a different title if there is something more appropriate. \$\endgroup\$Sᴀᴍ Onᴇᴌᴀ– Sᴀᴍ Onᴇᴌᴀ ♦2020年05月29日 15:31:16 +00:00Commented May 29, 2020 at 15:31
3 Answers 3
The function render()
in only supposed to render. It is not supposed to compute some style, set variables, have any logic other than render: (Functions Names Should Say What They Do). This should respect the SRP (Single Responsiblity Principle), as well as another clean code rule: 'A Function Should Do One Thing'.
What could be code smell in your first file:
- A unused constructor should not be there at all,
- The percentage calculation should be put in a function of its own
- The color choice should be placed in a function of its own
What could be code smell in your second file:
- A unused constructor should be removed
For both files, you could also add some prop types verifications using the library 'prop_types'.
As for your questions, with short answers:
- Not it's not Ok
- Depends on what you intend to do!
- This article should help you choose: React Functional or Class components ? - even though you can use hooks now as well :)
-
3\$\begingroup\$ welcome @Orlyyn - keep up the good work \$\endgroup\$Roman– Roman2020年03月07日 12:07:28 +00:00Commented Mar 7, 2020 at 12:07
-
\$\begingroup\$ @Orlyyn So Whatever received in props, should it be updated to state variable in componentDidMount()? \$\endgroup\$Dheemanth Bhat– Dheemanth Bhat2020年03月08日 13:36:27 +00:00Commented Mar 8, 2020 at 13:36
-
\$\begingroup\$ Short answer: No, because
componentDidMount
does not fire when your component receives updated props, so if you get updated props (like changed props overtime), your component won't update. Instead, you could usecomponentDidUpdate
. However it also depends, again, on what you want to do... \$\endgroup\$Orlyyn– Orlyyn2020年03月09日 08:55:58 +00:00Commented Mar 9, 2020 at 8:55
The answer by Orlyyn explains it well. Just adding to it:
- You can probably destructure your variables, this helps with readability and reuse.
- Since you are not using the state of the class you can convert that into
Functional Component
- Use
template string
instead of doing it in bits. - Still no need to add
this.state
and callsetState
in yourcomponentDidMount()
. What Orlyyn meant by single responsibility principle was that there shouldn't be any other logic in there, simply. You can still get the variables that you need for that function to work.
The State
is useful when you need to manipulate it within your very class or function.
So, a refactor of your code batch_progress.js could be as following:
import React from 'react';
import PropTypes from 'prop-types';
import ProgressBar from '../progress_bar/progress_bar';
const statusCodeColors = {
100: '#e7e4f1',
200: '#c3dcec',
300: '#ecc6eb',
400: '#ecdec3',
500: '#c8ecc7',
};
const getStatusColor = (code) => statusCodeColors[code] || '#e7e4f1';
const getPercentage = (num, total) => (num / total) * 100;
const BatchStatus = ({ batch: { number, status }, targetBatchCount }) => {
const color = getStatusColor(status);
const percentage = getPercentage(number, targetBatchCount);
return (
<ProgressBar foregroundColor={color} percentage={percentage}>
{`${number} / ${targetBatchCount}`}
</ProgressBar>
);
};
BatchStatus.defaultProps = {
batch: {
number: 50,
status: 100,
},
targetBatchCount: 100,
};
BatchStatus.propTypes = {
batch: PropTypes.shape({
number: PropTypes.number,
status: PropTypes.number,
}),
targetBatchCount: PropTypes.number,
};
export default BatchStatus;
Included the prop-types
there. Might help you in getting started with it. Though react has a great documentation for it.
I have also replaced your switch-case
statement there with something more cleaner. You can read about it in following articles:
File 1: batch_progress.js
import React, { Component } from 'react';
import ProgressBar from '../progress_bar/progress_bar';
export default class BatchStatus extends Component {
constructor(props) {
super(props);
this.state = {
color: ''
}
}
componentDidUpdate = (prevProps, prevState) => {
if (this.props === prevProps) {
return;
}
this.buildProgressBar();
}
componentDidMount = () => {
this.buildProgressBar();
}
buildProgressBar = () => {
let color;
let percentage = (this.props.batch.number / this.props.targetBatchCount) * 100;
switch (this.props.batch.status) {
case 100:
color = '#e7e4f1';
break;
case 200:
color = '#c3dcec';
break;
case 300:
color = '#ecc6eb';
break;
case 400:
color = '#ecdec3';
break;
case 500:
color = '#c8ecc7';
break;
default:
color = '#e7e4f1';
}
this.setState({
color: color,
percentage: percentage
})
}
render() {
return (
<ProgressBar foregroundColor={this.state.color} percentage={this.state.percentage}>
{this.props.batch.number} / {this.props.targetBatchCount}
</ProgressBar>
);
}
}
File 2: progress_bar.js
import React, { Component } from 'react';
import './progress_bar.css';
export default class ProgressBar extends Component {
render() {
let foregroundColor = this.props.foregroundColor || '#e7e4f1';
let percentage = this.props.percentage || 0;
let backgroundColor = this.props.backgroundColor || '#eceeef';
let style = {
backgroundImage:
'linear-gradient(to right, ' +
foregroundColor +
' ' +
percentage +
'%, ' +
backgroundColor +
' 0%)'
};
return (
<div className="progress-bar-container" style={style}>
{this.props.children}
</div>
);
}
}