How to make React slick slider work with icons? - javascript

There is a code that displays icons
switch (name) {
case Header.Arrows.name:
return <ArrowsComponent key={name} color={color}/>;
case Header.Zoom.name:
return <ZoomTool key={name} color={color}/>;
default:
return null;
}
I want to not just display them but do it using the react slick slider. ArrowsComponent and ZoomTool are the components for icons. How to properly wrap this code in <Slider> .. </Slider>?

Here are my two ways
Method 1:
switch (name) {
case Header.Arrows.name:
return (
<Slider>
<ArrowsComponent key={name} color={color}/>
</Slider>
);
case Header.Zoom.name:
return (
<Slider>
<ZoomTool key={name} color={color}/>
</Slider>
);
default:
return null;
}
Method 2
const renderSlider = (child) => {
return (
<Slider>
{child}
</Slider>
);
};
switch (name) {
case Header.Arrows.name:
renderSlider(<ArrowsComponent key={name} color={color}/>);
case Header.Zoom.name:
renderSlider(<ZoomTool key={name} color={color}/>);
default:
return null;
}
Hope that helps.

Related

Elegant ways of handling conditional rendering of multiple components

Say I have a wizard-like view with an arbitrary number of steps:
const StepsComponent = () => {
const [stage, setStage] = useState(1);
const stageProps = {stage, setStage};
const stageMachine = () => {
switch (stage) {
case 1:
return <One {...stageProps} />;
case 2:
return <Two {...stageProps} />;
case 3:
return <Three {...stageProps} />;
default:
return <One {...stageProps} />;
}
};
return (
<>
{stageMachine()}
</>
);
}
Are there more elegant ways of handling such cases, other than switch statements or ternary expressions?
If I would have wizards with 10+ steps, then it'd be a real mess to manage it.
Probably I could do something like this but this seems hacky, doesn't it?
const stageMachine = Object.freeze({
1: <One {...stageProps} />,
2: <Two {...stageProps} />,
3: <Three {...stageProps} />
});
Also I don't like the idea of invoking stageMachine function in return, it is considered a bad practice?
You can try this
const StepsComponent = () => {
const [stage, setStage] = useState(1);
return (
<>
{stage === 1 && <One />}
{stage === 2 && <Thow />}
{stage === 3 && <Three />}
</>
);
}

Test map function with jest

I have a problem with testing this component that has a map function for rendering various icontype:
import { FaSwimmer, FaWifi, FaCoffee, FaUtensils, FaSnowflake, FaSmokingBan, FaCocktail, FaPaw, FaCar, FaConciergeBell, FaDumbbell, FaSpa, FaTv } from "react-icons/fa";
import "./Characteristics.css";
function Characteristics(props) {
const { productCharacteristics, page } = props;
function parseIcons(icon) {
case 'FaWiFi':
return <FaWifi className="service-icon-home" />
case 'FaSwim':
return <FaSwimmer className="service-icon-home swimmer-icon" />
case 'FaCoffee':
return <FaCoffee className="service-icon-home" />
case 'FaUtensils':
return <FaUtensils className="service-icon-home" />
case 'FaSnowflake':
return <FaSnowflake className="service-icon-home" />
case 'FaSmokingBan':
return <FaSmokingBan className="service-icon-home" />
case 'FaCocktail':
return <FaCocktail className="service-icon-home" />
case 'FaPaw':
return <FaPaw className="service-icon-home" />
case 'FaCar':
return <FaCar className="service-icon-home" />
case 'FaConciergeBell':
return <FaConciergeBell className="service-icon-home" />
case 'FaDumbbell':
return <FaDumbbell className="service-icon-home" />
case 'FaSpa':
return <FaSpa className="service-icon-home" />
case 'FaTv':
return <FaTv className="service-icon-home" />
}
}
};
if (page === "home") {
return (
<ul className="services-icons">
{productCharacteristics.map((characteristic) => (
<li className="service-icon" key={characteristic.id}>
{parseIcons(characteristic.icon)}
</li>
))}
</ul>
)
} else {
return (
<ul className="services">
{productCharacteristics.map((characteristic) => (
<li className="service" key={characteristic.id}>
{parseIcons(characteristic.icon)}
<span>{characteristic.name}</span>
</li>
))}
</ul>
);
};
};
export default Characteristics;
The test in jest for render list of characteristics is
import React from 'react'
import {screen, render, within} from '#testing-library/react'
import Characteristics from './Characteristics'
beforeEach(() => render(<Characteristics />));
describe('Test for Characteristics', () => {
test('Render list of characteristics"', () => {
const list = screen.getByRole("list", {
name: "",
})
const {getAllByRole} = within(list)
const items = getAllByRole("listitem")
expect(items.length).toBe(13)
});
});
The error in this line {productCharacteristics.map((characteristic) and console is:
TypeError: Cannot read property 'map' of undefined

How can I test a switch case that depends on a parameter?

I have this:
const renderComponents = () => {
switch (selectedService) {
case 'otherservices':
return <SoftLayerCancellationRequests />;
case 'dedicatedhosts':
return <GetDedicatedHostsCancellations />;
case 'virtualguestsservers':
return <SoftLayerGetVirtualGuests />;
case 'baremetalservers':
return <GetBareMetalServersCancellations />;
default:
return null;
}
};
Which at the end is called on the return statement of the component:
return (
<>
<Header pageTitle={t('cancellations.header')} />
{accountId ? (
<>
<TableToolbarComp />
{renderComponents()}
</>
) : (
<UpgradeMessage />
)}
</>
);
And the selectedService parameter is coming from a store:
export default compose(
connect(store => ({
accountId: store.global.softlayerAccountId,
selectedService: store.cancellations.selectedService,
})),
translate(),
hot(module),
)(Cancellations);
What can I do to test that switch case?
The function under renderComponents should accept selectedService as a parameter:
const renderComponents = (selectedService) => {
switch (selectedService) {
// ...
}
};
By not relying on a closure, the function becomes pure and is way easier to unit test :
it('renders a SoftLayerCancellationRequests when passed "otherservices" as parameter', () => {
const wrapper = shallow(renderComponents('otherservices'));
expect(wrapper.find(SoftLayerCancellationRequests)).toHaveLength(1);
})
Yet, I see little value in such tests. This is because the function basically acts as a simple map :
const serviceToComponent : {
otherservices: SoftLayerCancellationRequests,
dedicatedhosts: GetDedicatedHostsCancellations,
virtualguestsservers: SoftLayerGetVirtualGuests,
baremetalservers: GetBareMetalServersCancellations
}
which seems a bit dull to test.
A more meaningful test would be to test the behaviors of the component that uses such a mapping.

Return First Item in Index in React Component

Update to question for clarification: What I'm trying to do here is for every instance where the index === 0, i want to conditionally apply a black class (recentTitleClass) to the typography text. I am passing the two css classes previousTitleClass & recentTitleClass into the component through props. Right now I only want to recentTitleClass used for only the first instance of the array. This array changes if a new comment/title is added, hence the labeling of previousTitleClass & recentTitleClass.
Here is what I have so far.
interface IProps {
comments?: List<Map<{}, {}>>;
previousTitleClass?: string;
recentTitleClass?: string;
}
type Props = IProps & WithStyles<typeof styles>;
class Component extends React.Component<Props> {
public render(): React.ReactNode {
const { comments } = this.props;
if (!comments || comments.count() <= 0) {
return null;
}
return comments.map((comment, index) => {
const shouldHaveClass = index === 0;
return (
comment && (
<React.Fragment key={index}>
{this.renderComment(comment, shouldHaveClass)}
</React.Fragment>
)
);
});
}
private renderComment(comment: Map<{}, {}>, shouldHaveClass:any) {
const { classes, previousTitleClass, recentTitleClass } = this.props;
const recentTitleClass = shouldHaveClass ? "commentFromOsbpSupport" : null;
let from: React.ReactNode;
switch (comment.getIn(["from", "role"])) {
case "ROLE_MENTOR":
from = (
<div>
<Typography
variant="body2"
className={classnames(
classes.commentFromMentor,
"comment-from comment-from--mentor",
previousTitleClass,
recentTitleClass
)}>
Mentor POC
</Typography>
</div>
);
break;
case "ROLE_OSBP_SUPPORT":
from = (
<Typography
variant="body2"
className={classnames(
classes.commentFromOsbpSupport,
"comment-from comment-from--osbp_support",
previousTitleClass,
recentTitleClass
)}>
Mentor Protégé Program Reviewer
</Typography>
);
break;
default:
from = (
<Typography variant="body2" className="comment-from">
Unknown Commenter
</Typography>
);
break;
}
--------------
how the component is being used in another component
<CommentHistory comments={comments} previousTitleClass={classes.previousTitleClass} recentTitleClass={classes.recentTitleClass}/>
so I don't know exactly what you are asking for but here's an example:
return comments.map((comment, index) => {
const shouldHaveClass = index === 0;
return (
comment && (
<React.Fragment key={index}>
{this.renderComment(comment, shouldHaveClass)}
</React.Fragment>
)
);
});
And then update your renderComment to accept another parameter
renderComment(comment: Map<{}, {}>, shouldHaveClass:any
And then finally add
// <---- here
const shouldHaveClassName = shouldHaveClass ? 'IHAVETHECLASS' : null;
<Typography
variant="body2"
className={classnames(
classes.commentFromMentor,
"comment-from comment-from--mentor",
previousTitleClass,
recentTitleClass,
shouldHaveClassName // <---- here
)}>
you can add special style inside renderComment
if (!comments || comments.count() <= 0) {
return null;
}
return comments.map((comment, index) => {
const style = {
color: "red"
}
return (
comment && (
<React.Fragment key={index}>
{this.renderComment(comment,index===0?style:null)}
</React.Fragment>
)
);
});
Simply wrap your comment function in a div and change its classname depending on the index. You can then use a ternary condition to decide which class to apply :
public render(): React.ReactNode {
const { comments } = this.props;
if (!comments || comments.count() <= 0) {
return null;
}
return comments.map((comment, index) => {
return (
comment && (
<React.Fragment key={index}>
<div className={index ? 'notFirst' : 'first'}>
{this.renderComment(comment)}
</div>
</React.Fragment>
)
);
});
}
You can also send the classname to your this.renderComment if you want to :
comment && (
<React.Fragment key={index}>
{this.renderComment(comment, index ? 'notFirst' : 'first')}
</React.Fragment>
)
And add a second parameter in your renderComment function, allowing you to apply the className of the component.
You can then apply different rules in your CSS based on these class names :
.first {
color: black;
}
.notFirst {
color: gray;
}

Matching strings to components React

I'm making a Calendar which consists of an header and calendar. The header is for picking the type of calendar; weekly or monthly.
I had to make a dummy component called CalendarPicker just so I can use a switch. Inline switch is what I think needed but jsx doesn't accept it.
Is there a better way to do this? Or another way to match strings to components?
<CalendarController
render={({ type, onTypeClick }) => (
<>
<header>
<p>header of agenda</p>
<button onClick={onTypeClick("weekly")}>weekly</button>
<button onClick={onTypeClick("monthly")}>monthly</button>
</header>
<CalendarPicker
type={type}
render={type => {
switch (this.props.type) {
case "monthly":
return <MonthlyCalendar />;
case "weekly":
return <WeeklyCalendar />;
default:
return <MonthlyCalendar />;
}
}}
/>
</>
)}
/>
This is what I did to achieve this. In my case there were around 50 components and according to the name in the string I had to render that component.
I created a file ComponentSelector.js which imports all the components.
ComponentSelector.js
export default const objComponents = {
MonthlyCalendar : {
LoadComponent: function () {
return require('../../Modules/MonthlyCalendar ').default;
}
},
WeeklyCalendar : {
LoadComponent: function () {
return require('../../Modules/WeeklyCalendar ').default;
}
}
}
Import it into your CalendarController component
import objComponents from './ComponentSelector.js';
render(){
var CalComp=objComponents[this.props.type].LoadComponent();
return(<div>
<header>
<p>header of agenda</p>
<button onClick={onTypeClick("weekly")}>weekly</button>
<button onClick={onTypeClick("monthly")}>monthly</button>
</header>
<CalComp type={type}/>
</div>)
}

Categories