I'm building a carousel in react. The carousel is passed an array of slides and these are cloned as needed depending on how many slides must be shown. This is useful for infinite scrolling for example, where the width of the screen may require more slides than the ones I'm passing to the component. As an example, I can pass 3 slides to the carousel but because the user zoomed out a lot, 10 slides fit the total width, so 10 slides are shown that are just copies of that 3 initial slides.
The main problem I am facing is that when I need to build the cloned slides, I first need the parent component width to know how many I should be creating. The reference to the component at this time hasn't been yet resolved so I can't use it and modify the DOM in the useEffect or useEffectLayout seems not to be the way to go with react. So, how could I get around this?
This is how I use the carousel:
<Carrousel startingSlide={0}>
{
productData.slice(0,slidesCount).map( (o, index)=>{
let key = "slide-content-"+index;
return <div key={key} id={key} className="carousel-item">{o.title}</div>
})
}
</Carrousel>
And here how the carousel tries to build the needed cloned slides when rendering:
return (
<section className="carrousel-container" ref={containerRef}>
{
children.length ? buildSliderElementsForWidth("HERE I NEED THE CONTAINER WIDTH") : "NO DATA"
}
</section>
);
Related
I am using the React-slick slider to display the images given by the random user API.
I followed the steps given on the npm page for the react slider and installed the slick carousel and added the two CSS files to the component.
I wanted to add more images to the existing slider if the user clicked on the next arrow or dragged the slider to the left, so im using the afterChange callback to update my state so that the useEffect having this state value as the second argument can be called and then concat the previous data with the new data.
Here I noticed when the user clicks next or drags the slider to the left sometimes there is a distortion.
https://stackblitz.com/edit/react-nlxodz has one slider and one text line below it, slide the slider continuously and you can see that for a few brief seconds the text under the slider gets pushed even further down and then comes back up to the original place.
Documentation suggests the below CSS if there is a flex prop on the slider. However, my code doesn’t have flex properties.
Flexbox support
If you have flex property on container div of slider, add below css
* {
min-height: 0;
min-width: 0;
}
is this issue raised because of the way im adding data to the slider or an issue with the CSS? is there a solution where that distortion is not shown when the user swipes or slides very fast?
Wrap Slider with div
<div style={{ backgroundColor: "green", height: "140px" }}>
<Slider {...settings}>
{rowData.map(i => (
<div>
<img src={i.picture.large} />
</div>
))}
</Slider>
</div>
<div>KEEP AN EYE ON THIS TEXT WHILE SCROLLING</div>
I'm developing a numerical Slider component in React. It actually works right now and is fully functional, but there is a single issue. I set the width of the thumb and total slider via CSS, and I like doing it that way, as it's flexible.
The slider and thumb width is also needed for calculations, such as calculating the max position of the slider, or the position of the thumb relative to the absolute.
So, I have functions like this:
getSliderWidth = () => {
return this.sliderRef.current ? this.sliderRef.current.offsetWidth : 0;
}
getThumbWidth = () => {
return this.sliderThumbRef.current ? this.sliderThumbRef.current.clientWidth : 0;
}
Where the refs are defined in the render function like so:
<div ref={this.sliderRef} className="slider-range">
<div className="slider-range-connect" style={connectStyle}></div>
<div ref={this.sliderThumbRef} className="slider-range-thumb" style={thumbStyle}></div>
</div>
The issue with this, though, is that the widths are only known after the first render. The refs aren't available until it is first rendered. So, I think what I need to do is force a re-render, such that when the component is initially loaded, it is rendered one more time. This is because the initial render function needs to know the relative max position and thumb position in order to render the initial elements.
So, is there a "React" way to do this, or am I missing something? Is the ideal solution here to have some sort of boolean flag, and in the initial mount function, to check this flag, and if it is the first render, to do another render, and then to set the flag? That doesn't seem very "React"ish, so I was wondering if there is something more elegant.
I'm using the React-virtualized package, Masonry component.
My problem is with the <div class="ReactVirtualized__Masonry__innerScrollContainer"> element.
When I load a list of 50 items, then filter that list down to five items, the height of this div doesn't shrink or change at all. For instance, at 50 items, the element is set to <div class="ReactVirtualized__Masonry__innerScrollContainer" style="... height='5000px' ...">, and when the list gets filtered to five items, the height in this div doesn't shrink to, say 500px.
Consequently, there's 4500px of white space below my five items and above the page footer. This extra whitespace makes for a poor user experience.
I'm using:
react#16.4.1
react-virtualized#9.18.5
redux#3.7.2
This div is a child of the <Masonry> component, and I don't see how I can hook into it via a callback and tell it to update when the list item count changes.
Can somebody please tell me how to make this div's height change when the list gets smaller after being filtered?
When you filter your list down from 50 items to 5 items, you also need to clear your CellMeasurerCache, reset your cellPositioner created with createMasonryCellPositioner, and clearCellPositions on your Masonry ref (Official CodeSandbox example).
cache.clearAll();
cellPositioner.reset(cellPositionerConfig);
this.masonryRef.clearCellPositions();
I am attempting to create an easy-to-use UI/UX selection system.
Essentially, on the viewport, I first have 3 "difficulty" components that choose what "difficulty level" you want.
Once clicked, they should then transition to the next selection phase, which would be "male" or "female".
Clicking this button should move/remove the difficulty level component to the left (out of the viewport), and move the sex selection into the viewport.
How would I implement this?
I also plan on implementing a "Go back" feature as well in the future, so that users can go back and forth from Difficulty and Sex components.
My ideas
Once the button is clicked, I just use CSS to transition the difficulty component out of the viewport, and the "sex" component into the viewport. After the transition, I give that component a display: none to remove it completely from the user.
Concerns: This doesn't seem efficient. Should I be removing the component entirely? If so, where does one begin to do that?
Another method would be to remove/add the components as needed...which I believe would require using the ComponentDidMount() and ComponentDidUnmount() functions, and then using the React Transition Group library to somehow transition them out?
Here is an excellent, Picasso-like, hand-drawn example from myself:
There is how to do the transition.
Typically, setting display: none stops any sort of animation, which you don't want to do.
export default class Modal extends React.Component {
shouldComponentUpdate(nextProps, nextState) {
return (
nextProps.show !== this.props.show ||
nextProps.children !== this.props.children
);
}
render() {
const { show, children } = this.props;
return (
<div
style={{
transform: show ? 'translateY(0)' : 'translateY(-100vh)',
opacity: show ? 1 : 0,
}}
>
{children}
</div>
);
}
}
Note that returning false from shouldComponentUpdate will stop re-rendering the modal and its children.
The children could be anything or nothing. So when you don't want to show it, render an empty div outside view window is very efficient.
Key takeaway
display: none shouldn't need most of the time. It doesn't support animation, and render function can return <div /> or null.
React components will re-render when received new props or updated state, regardless display type and window position.
Mare sure have a clear understanding on rendering lifecycle, not all mounting/updating functions can setState, and you can stop re-rendering manually.
I created a carousel with React.js, it was simple until I arrived at the animation problem. The carousel is classic, it is composed of "slides" of content, of small bullets indicating the current slide, and of small thumbnails for navigating between the slide.
The carousel component is data-driven, meaning that it is passed its content as a javascript array of objects. Each slide is a li tag within a ul, and just have to change the margin-left css property of the ul to move from one slide to another.
I'm wondering if I should use the ReactTransitionGroup or ReactCSSTransitionGroup to animate the transition from one slide to another. Basically the transition is a sliding effect from left to right when going from one slide to another.
My understanding is that the ReactTransitionGroups API is helpful when adding or removing some content. Here I won't add/remove any slide, change changing the visible one with an animation.
My difficulty wrapping my head around this is that I developped a static (aka without animation) carousel where the currently displayed slide is the only state saved in the component. This state is just the index of the slide in the array of slides. So when I click a thumbnail to navigate slide number n, the only thing I do is updating this internal state, then the rendering takes care of setting the left style property based on this index.
I don't see how I can add animation to this carousel. Any help/hint greatly appreciated.
The answer was fairly simple, no need to use ReactTransitionGroup or ReactCSSTransitionGroup. I simply used inline css with css3 transitions.
In the render function, we dynamically calculate the left property. As our slides all have the same fixed width, the slides are displayed inline and only one slide is made visible thanks to overflow: hidden on the parent element. Our dynamic class code looked like this :
var styles = {
position: "absolute",
top: 0,
left: IMG_WIDTH * (this.props.idx - this.props.activeIdx),
zIndex: 100,
transition: 'left 1s',
width: '100%'
};
Don't look at the formula too much, it's an implementation detail.
Further note, our carousel is "infinite", meaning that the transition always go one way - from left to right - even when on the first or last element. It was "just" a matter of playing with the indices of the array of content. This part was a bit harder than the carousel itself.
Side note (even troll) : even the hard part was better that doing tricky and cabalistic direct DOM manipulation since it was pure algorithms with data. No more jQuery for this stuff, and even for the rest of our website.