I’m building a carousel which contains a main image and a list of thumbnail images.
There are prev and next buttons to allow the user to navigate through the list of images.
Here is my code so far:
import styles from './carousel.css';
import cn from '../../../utils/classname';
import actions from '../../../actions';
import Magnified from '../../../svg/icons/ui/magnified_glass';
import ArrowRight from '../../../svg/icons/ui/arrow_right';
import ArrowLeft from '../../../svg/icons/ui/arrow_left';
const Carousel = ({ dispatch, selectedCaravan }) =>
<div className={cn(styles.carouselWrap)}>
<div className={cn(styles.carouselFeatWrap)}>
<a href="#" className={cn(styles.carouselExpand)} onClick={() => dispatch({ type: actions.CAROUSEL_EXPAND })}>
<Magnified />
</a>
<ul className={cn(styles.carousel)}>
{selectedCaravan.images && selectedCaravan.images.map((image, i) => {
return <li key={i}>
<img src={image} />
</li>;
})}
</ul>
</div>
<div className={cn(styles.carouselThumbNavWrap)}>
<ul className={cn(styles.carouselThumbnails)}>
{selectedCaravan.images && selectedCaravan.images.map((image, i) => {
return <li key={i} onClick={() => dispatch ({ type: actions.CAROUSE_GO_TO })}>
<img src={image} />
</li>;
})}
</ul>
<div className={cn(styles.carouselNavigation)}>
<a href="#" className={cn(styles.carouselNavPrev)} onClick={() => dispatch({ type: actions.CAROUSEL_PREV })}>
<ArrowLeft />
</a>
<a href="#" className={cn(styles.carouselNavNext)} onClick={() => dispatch({ type: actions.CAROUSEL_NEXT })}>
<ArrowRight />
</a>
</div>
</div>
</div>;
export default Carousel;
I have actions such as CAROUSEL_NEXT
and CAROUSEL_PREV
. I am listening for these actions within my sagas and my thinking on this is I need to update the selected index and somehow update the main image to whichever the user has selected.
My saga looks like this so far:
const carouselPrev = function* (payload) {
const updateSelectedIndex = payload.updateSelectedIndex;
if (updateSelectedIndex) {
return false;
}
yield put({ type: actions.CAROUSEL_PREV, payload: updateSelectedIndex });
};
I’m unsure how to update the selected index when a user selects a new image and how to animate or essentially make the carousel slide.
I think you don’t need the saga at all.
You just define the actions for the reducer
// Action creators
const selectNext = () => ({
type: 'SELECT_NEXT',
})
const selectPrev = () => ({
type: 'SELECT_PREV',
})
const selectById = (id) => ({
type: 'SELECT_BY_ID',
payload: id,
})
// Reducer
const initial = {
selectedImageId: 0,
/* other state */
}
function reducer(state = initial, action) {
switch(action.type) {
case 'SELECT_NEXT':
return {
...state,
selectedImageId: state.selectedImageId + 1,
}
case 'SELECT_PREV':
return {
...state,
selectedImageId: state.selectedImageId - 1,
}
case 'SELECT_BY_ID':
return {
...state,
selectedImageId: action.payload,
}
default:
return state
}
}
after this you pass the callbacks from react-redux
const Component = ({ selectedImageId, onNext, onPrev, onSelect }) => (
<div>
<CarouselMainImage
id={selectedImageId} // this component will know which image to display based on this id
/>
{/* ... */}
<CarouselImages
onClick={onSelect}
/>
{/* ... */}
<PrevBtn
onClick={onPrev}
/>
<NextBtn
onClick={onNext}
/>
{/* ... */}
</div>
)
const mapStateToProps = state => ({
selectedImageId: state.selectedImageId
})
const mapDispatchToProps = dispatch =>
// use action creators here
bindActionCreators({
onNext: onSelectNext,
onPrev: onSelectPrev,
onSelect: onSelectById,
}, dispatch)
const ConnectedComponent = connect(mapStateToProps, mapDispatchToProps)
For transitions, you could use this: https://github.com/reactjs/react-transition-group