###Suggestions
Suggestions
###Nit-picky Suggestions
Nit-picky Suggestions
###Suggestions
###Nit-picky Suggestions
Suggestions
Nit-picky Suggestions
Sorry you didn't get the position, but perhaps the interviewers/code reviewers were looking for something else or some very specific things.
You cannot, in fact, use useSelector
or useDispatch
, nor any other react hook as they are only compatible with functional components. Other than that this appears to be clean and readable code, although it does have some redundancy.
###Suggestions
- The constructor doesn't actually do anything, so it can be removed
- All the class functions simply proxy props that are passed, so they, too, can be removed
- This is debatable, but IMO you should explicitly map the actions to props that you will use, it makes it clearer what the component can do
- The connect HOC's second parameter
mapDispatchToProps
automagically wraps each actionCreator with a call to dispatch as well - It appears
this.props.expenses
object shape is identical to the propsExpenseTable
takes, so you can spread those in, more DRY
###Nit-picky Suggestions
- Try to be as precise/explicit when defining proptypes
- Consistently use semi-colons
- In react only Components are PascalCased, most other variables and objects should be normal camelCased
- Destructure props to be more DRY, i.e. much less
this.props.X
,this.props.Y
,this.props.Z
. This one is debatable however as the argument against is that not destructuring them it is easy to see what is a prop versus state versus neither. I say you can just look to the top of the function where variables should normally be defined anyway to glean these details.
Component
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { PropTypes } from 'prop-types';
import ExpenseTable from '../components/ExpenseTable';
import {
CancelEditing,
CreateExpense,
DeleteExpense,
StartEditing,
UpdateExpense,
} from '../actions/ExpenseActions';
export class ExpenseContainer extends Component {
render() {
const {
CancelEditing,
CreateExpense,
DeleteExpense,
expenses,
StartEditing,
UpdateExpense,
} = this.props;
return (
<div className="expense-container">
<ExpenseTable
{...expenses}
createExpense={CreateExpense}
startEditing={StartEditing}
cancelEditing={CancelEditing}
editExpense={UpdateExpense}
deleteExpense={DeleteExpense}
/>
</div>
);
}
}
ExpenseContainer.propTypes = {
CancelEditing: PropTypes.func.isRequired,
CreateExpense: PropTypes.func.isRequired,
DeleteExpense: PropTypes.func.isRequired,
StartEditing: PropTypes.func.isRequired,
UpdateExpense: PropTypes.func.isRequired,
expenses: PropTypes.shape({
expenses: PropTypes.string.isRequired, // or number or whatever the specific type is
subTotal: PropTypes.string.isRequired,
total: PropTypes.string.isRequired,
}).isRequired
};
function mapStateToProps(state) {
return {
expenses: state.expenses
}
};
const mapDispatchToProps = {
CancelEditing,
CreateExpense,
DeleteExpense,
StartEditing,
UpdateExpense,
};
export default connect(mapStateToProps, mapDispatchToProps)(ExpenseContainer);
A final suggestion would be to just convert ExpenseContainer
to a functional component since it doesn't use any of the class-based lifecycle functions.
export const ExpenseContainer = ({
CancelEditing,
CreateExpense,
DeleteExpense,
expenses,
StartEditing,
UpdateExpense,
}) => (
<div className="expense-container">
<ExpenseTable
{...expenses}
createExpense={CreateExpense}
startEditing={StartEditing}
cancelEditing={CancelEditing}
editExpense={UpdateExpense}
deleteExpense = {DeleteExpense}
/>
</div>
);
ExpenseContainer.propTypes = { ... };
function mapStateToProps(state) { ... };
const mapDispatchToProps = { ... };
export default connect(mapStateToProps, mapDispatchToProps)(ExpenseContainer);