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);
- 939
- 1
- 6
- 14