Virtually always, you will want to keep part of the default functionality and only modify some aspect of the existing file. This is how the theme is usually extended.
This is easy-to-achieve with class, where you can extend the original file providing some custom functionality. But what to do if an override of the constant or function is intended?
Following are the rules, which will help you to stay "compatible" (thus ensuring easier upgrades):
Instead of copy-pasting a file, prefer manually exporting original functions and constants, and then re-exporting ones you changed!
<aside>
ℹ️ The ScandiPWA import mechanism provides the Source
aliases to enable you to directly import from the parent theme, regardless of whether there is an overridden version available. Similarly, you can use the SourceRoute
alias to import directly from a route defined in the parent theme, or the SourceUtil
alias to import a utility file from the parent theme.
</aside>
Let's now consider an example. Here, we would like to override a MIN_PASSWORD_LENGTH
defined in the component/Form/Form.config.js
file. Here is how we can do it (without copying the file):
// exporting all functions and constants from original file
export * from 'SourceComponent/Form/Form.config.js';
// specifically exporting default (as it is not included in "*")
export { default } from 'SourceComponent/Form/Form.config.js';
// re-exporting the overriden variable
export const MIN_PASSWORD_LENGTH = 6;
Instead of copying the original function from the source file, consider importing and calling it, then processing the original output value.
Let's now consider an example. Here, we would like to override a mapDispatchToProps
defined in the component/AddToCart/AddToCart.container.js
file. Here is how we can do it (without copying the original function):
<aside> ⚠️ Heads up! When overriding a function that is used later in the component (for example in default export), you must also override the place the function is being used (therefore, as per example, default export).
</aside>
// imporing original function to call
import {
AddToCartContainer,
mapStateToProps,
mapDispatchToProps as sourceMapDispatchToProps
} from 'SourceComponent/AddToCart/AddToCart.container.js';
// importing to replicate original default export
import { connect } from 'react-redux';
// exporting all functions and constants from original file
export * from 'SourceComponent/AddToCart/AddToCart.container.js';
// re-exporting the overriden variable
export const mapDispatchToProps = (dispatch) => {
// calling the original function to modify the result
const handler = sourceMapDispatchToProps(dispatch);
// add custom functionality
handler.logProduct = () => {
console.log('product added to cart');
};
// returning modified result
return handler;
}
// exporting default
// (becuase function mapDispatchToProps was used in it)
export default connect(mapStateToProps, mapDispatchToProps)(AddToCartContainer);
<aside> ➡️ Always put comment before overridden function with explanation of override reason, See example:
</aside>
/**
* Overridden to add label rendering
*/
renderCardContent() {
const { renderContent } = this.props;
if (renderContent) {
return renderContent(this.contentObject);
}
return (
this.renderCardLinkWrapper((
<>
<div block="ProductCard" elem="FigureReview">
<figure block="ProductCard" elem="Figure">
{ this.renderPicture() }
{ this.renderLabel() }
</figure>
</div>
<div block="ProductCard" elem="Content">
{ this.renderReviews() }
{ this.renderAdditionalProductDetails() }
{ this.renderMainDetails() }
{ this.renderProductPrice() }
</div>
<div block="ProductCard" elem="VisibleOnHover">
{ this.renderVisibleOnHover() }
</div>
</>
))
);
}